java多线程基础(一)
java基础之多线程
1、线程生命周期
2、线程的创建有两种方式
(1)继承Thread类:
/*
* 创建一个子线程,完成1-100之间自然数的输出。同样的,主线程执行同样的操作。
* 创建多线程的第一种方式:继承Thread类。
*/
public class TestThread {
public static void main(String[] args) {
//3\创建一个子类对象
SubThread subThread1 = new SubThread();
SubThread subThread2 = new SubThread();
//4\调用线程的start()方法:启动此线程,调用线程的run()方法。
//一个线程只能执行一次start()
subThread1.start();
subThread2.start();
for(int i =1;i<10000;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
//1、继承Thread类
class SubThread extends Thread{
//2、重写run方法,方法类内实现此子线程压迫完成的功能
public void run(){
for(int i =1;i<10000;i++){
System.out.println(Thread.currentThread().getName()+":"+i);
}
}
}
/*
* Thread的chnagyong fangfa
* 1、start():启动线程并执行相应的run方法
* 2、run():子线程要执行的方法,放入run()方法中
* 3、currentThread():静态的,调取当前的线程
* 4、getName():获取此线程的名字
* 5、setName():设置此线程的名字
* 6、yield():调用此方法的线程释放当钱CPU的执行权。
* 7、join():在A线程中调用B线程的join()方法,表示,当执行到此方法,A线程停止执行,直至B线程执行完毕,A线程再接着执行。
* 8、isAlive():判断当前线程是否还存活。
* 9、sleep(long l):显示的让此线程睡眠l毫秒。
* 10、线程间通信:wait()、notify()、notifyAll()
*/
public class TestThread1 {
public static void main(String[] args) throws InterruptedException {
//3\创建一个子类对象
SubThread1 subThread1 = new SubThread1();
SubThread1 subThread2 = new SubThread1();
//4\调用线程的start()方法:启动此线程,调用线程的run()方法。
//一个线程只能执行一次start()
subThread1.setName("嘿嘿");
subThread1.start();
subThread1.setPriority(Thread.MAX_PRIORITY);
subThread2.start();
Thread.currentThread().setName("主线程");
for(int i =1;i<10000;i++){
//Thread.currentThread().sleep(1000);
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+"---"+i);
/*if(i%10==0){
Thread.currentThread().yield();
}*/
if(i==20){
subThread1.join();
}
}
}
}
//1、继承Thread类
class SubThread1 extends Thread{
//2、重写run方法,方法类内实现此子线程要完成的功能
public void run(){
for(int i =1;i<10000;i++){
System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority()+"---"+i);
}
}
}
(2)实现Runnable接口
/*
* 创建线程的第二种方法:通过实现Runnable 接口来实现
* 1、创建一个实现了Runable接口的类
* 2、实现接口的抽象方法
* 3、创建一个Runnable接口实现类的对象
* 4、对象作为形参传递给Thread类的构造器中,创建Thread对象,此对象即为一个线程
* 5、调用Thread类对象的start()方法。
*
* 对比一下继承和实现的方式
* 1、联系:都实现了Runnable接口。(继承中的THread类,底层也是实现了Runnable接口)
* 2、哪种方式比较好?实现的方式优于继承的方式》
* (1)实现的方式避免了java中单继承的局限性(因为一个类继承了Thread之后,就不能再继承其他类了)。
* (2)比如在售票例子中,多线程操作同一份数据,更适合使用实现的方式。
*/
class PrintNum implements Runnable{
@Override
public void run() {
for(int i = 0 ; i<=100 ; i++){
if(i%2 == 0){
System.out.println(Thread.currentThread().getName() +"---"+ i);
}
}
}
}
public class TestRunnable{
public static void main(String[] args) {
PrintNum p = new PrintNum();
//要想启动一个多线程,必须调用start()方法。
Thread t1 = new Thread(p);
t1.start();//启动线程执行Thread对象生成时,构造器形参的对象的run方法。
//再创建一个线程
Thread t2 = new Thread(p);
t2.start();
}
}
3、线程间同步问题
/*
* 此程序存在线程的安全问题,打印车票时,会出现重票和错票的问题。
*/
public class TestWindow1 {
public static void main(String[] args) {
Window1 window = new Window1();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class Window1 implements Runnable {
int sum = 100;
@Override
public void run() {
while(true){
if(sum> 0){
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"----"+sum);
sum--;
}else if(sum == 0){
System.out.println("这是最后一张票");
sum--;
}else {
break;
}
}
}
}
分别解决多线程继承和实现方式出现的问题:
(1)同步代码块
public class TestWindow3 {
public static void main(String[] args) {
Window3 w1 = new Window3();
Window3 w2 = new Window3();
Window3 w3 = new Window3();
w1.setName("窗口1");
w2.setName("窗口2");
w3.setName("窗口3");
w1.start();
w2.start();
w3.start();
}
}
class Window3 extends Thread{
public static int sum = 100;
static Object obj = new Object();
public void run(){
while(true){
synchronized (obj) {//在本题中,this表示w1、w2、w3。
if (sum > 0) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "----" + sum);
sum--;
}else {
break;
}
}
}
}
}
/*
* 此程序存在线程的安全问题,打印车票时,会出现重票和错票的问题。
* 1、存在的原因是什么?
* 由于一个线程在操作共享数据未执行完的情况下,另外的数据参与进来,导致共享数据存在安全问题。
*
* 2、如何解决线程的安全问题?
* 必须让一个操作共享数据完毕以后,其他线程才有机会参与共享数据的操作。
*
* 3、java如何实现线程的安全:线程的同步机制
* 方式一:同步代码块
* synchronized(对象(同步监视器)){
* //需要被同步的代码块(即为操作共享数据的代码)
* }
* (1)共享数据:多个线程共同操作的同一个数据或者变量
* (2)同步监视器(锁):由一个对象来充当。哪个线程获取此监视器,谁就能执行大括号里被同步的代码。
* 注:要求所有的线程必须使用同一把安全锁,才能实现同步。
* 在实现的方式中可以使用this作为同步锁,但是在继承的方式要慎用。
* 方式二:同步方法
* synchronized 还可以放在方法的声明中,表示整个方法为同步方法
* 例如:public synchronized void show(String name){
* ....
* }
* 注: 将操作共享数据的方法声明成synchronized 。即此方法为同步方法,能够保证当其中一个线程执行此方法时,其他线程在外等待,
* 直至此线程执行完此方法。
* 》同步方法的锁:就是当前对象this。
*/
public class TestWindow2 {
public static void main(String[] args) {
Window2 window = new Window2();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class Window2 implements Runnable {
int sum = 100; //共享数据
//Animal obj = new Animal();
@Override
public void run() {
while(true){
synchronized (this) {//在本问题中,this表示当前对象,本题中表示window,只有一个,所以此处可以使用this
if(sum> 0){
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"----"+sum);
sum--;
}else if(sum == 0){
System.out.println("这是最后一张票");
sum--;
}else {
break;
}
}
}
}
}
注:如果synchronized (this) {}包含住了while(true)这个代码块,那么控制台就会出现,只有一个线程在执行售票业务的情况。
(2)同步代码方法
注意:在继承Thread类方法中,不能使用synchronized方法,因为锁对象不是唯一的,所以依旧会出现同步问题。
/*
* 此程序存在线程的安全问题,打印车票时,会出现重票和错票的问题。
*/
public class TestWindow4 {
public static void main(String[] args) {
Window4 window = new Window4();
Thread t1 = new Thread(window);
Thread t2 = new Thread(window);
Thread t3 = new Thread(window);
t1.setName("窗口1");
t2.setName("窗口2");
t3.setName("窗口3");
t1.start();
t2.start();
t3.start();
}
}
class Window4 implements Runnable {
int sum = 100;
@Override
public void run() {
while(true){
show();
}
}
public synchronized void show(){
if (sum > 0) {
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "----" + sum);
sum--;
}
}
}
4、单例模式(懒汉式)中关于多线程同步的解决问题
/*
* 关于懒汉式的线程安全问题,使用同步机制,对于一般的方法内,使用同步代码块,可以考虑使用this作为同步锁。
* 对于静态方法,使用当前类本身充当锁
*/
public class TestSingleTon {
public static void main(String[] args) {
SingleTon s1 = SingleTon.getInstance();
SingleTon s2 = SingleTon.getInstance();
System.out.println(s1 == s2);
}
}
class SingleTon{
private SingleTon(){}
private static SingleTon instance = null;
public static SingleTon getInstance(){
//加上下边这个if判断语句,程序的效率会提高不少
if(instance == null){
synchronized (SingleTon.class) {
if(instance == null)
instance = new SingleTon();
}
}
return instance;
}
}
5、多线程实例:实现两个人往银行账户中存钱
/*
* 实现两个人往银行账户中存钱:方式一:采用继承的方法
*/
public class TestAccount {
public static void main(String[] args) {
Account2 account2 = new Account2();
Customer2 a1 = new Customer2(account2);
Customer2 a2 = new Customer2(account2);
a1.setName("账户1");
a2.setName("账户2");
a1.start();
a2.start();
}
}
class Account2{
private double balance;
public Account2(){
}
public synchronized void deposit(double amt){
this.balance += amt;
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"操作后,"+this.balance);
}
}
class Customer2 extends Thread{
Account2 account;
public Customer2(Account2 account){
this.account = account;
}
public void run(){
for(int i = 0 ;i<3;i++){
account.deposit(1000);
}
}
}
/*
* 实现两个人往银行账户中存钱:方式二:采用实现的方法
*/
public class TestAccount1 {
public static void main(String[] args) {
Account account = new Account();
Customer c = new Customer(account);
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
class Customer implements Runnable {
private Account account = null;
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public Customer() {
super();
}
public Customer(Account account) {
super();
this.account = account;
}
@Override
public void run() {
synchronized (this) {
for (int i = 0; i < 3; i++) {
account.setMoney(1000);
}
}
}
}
class Account {
private int money = 0;
public Account() {
System.out.println("账户现有:" + money);
}
public Account(int money) {
this.money = money;
System.out.println("账户现有:" + this.money);
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money += money;
System.out.println(Thread.currentThread().getName() + "-----" + money);
System.out.println("账户余额是:" + this.money);
}
}
6、实现线程之间的通信(使用wait()、notify()、notifyAll())
/*
* 线程通信:如下的三个关键字使用的话,都得在同步代码块或者同步方法中
* wait():一旦一个线程执行到wait方法,就释放当前的锁。
* notify():唤醒wait()的一个线程
* notifyAll():唤醒wait()的所有线程
*/
class PrintNum implements Runnable{
int num = 0;
@Override
public void run() {
while(true){
synchronized (this) {
notify(); //在此处加notify,意思是,第一个线程执行结束,释放锁,第二个线程进来之后,
//首先已经获取锁了,然后再唤醒另一个线程(虽然此时唤醒,但是也只能等到第二个线程释放锁之后,第一个线程才能再次开始执行)。
if(num <= 100){
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "-----"
+ num);
num++;
}
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class TestCommunication {
public static void main(String[] args) {
PrintNum printNum = new PrintNum();
Thread t1 = new Thread(printNum);
Thread t2 = new Thread(printNum);
t1.start();
t2.start();
}
}
/*
* 实现两个人往银行账户中存钱:方式一:采用继承的方法
*/
public class TestAccount {
public static void main(String[] args) {
Account2 account2 = new Account2();
Customer2 a1 = new Customer2(account2);
Customer2 a2 = new Customer2(account2);
a1.setName("账户1");
a2.setName("账户2");
a1.start();
a2.start();
}
}
class Account2{
private double balance;
public Account2(){
}
public synchronized void deposit(double amt){
notify();
this.balance += amt;
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"操作后,"+this.balance);
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Customer2 extends Thread{
Account2 account;
public Customer2(Account2 account){
this.account = account;
}
public void run(){
for(int i = 0 ;i<3;i++){
account.deposit(1000);
}
}
}
7、死锁
/*
* 死锁问题,处理线程同步时,容易出现这个问题
* 不同的线程分别占用对方的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
* 如下例:第一个线程在执行的时候,首先握住sb1这个锁,要想释放sb1锁,必须先要执行完里面握住sb2锁的操作执行完毕才可以。但是在这个过程中,另一个线程可能在第一个线程拿到sb2锁,并且第二个线程也需要调用sb1锁才能释放sb2锁,这样就会导致双方都握住对方的锁,但是都不能执行,从而造成死锁。
*/
public class TestDeadLock {
static StringBuffer sb1 = new StringBuffer();
static StringBuffer sb2 = new StringBuffer();
public static void main(String[] args) {
new Thread(){
public void run(){
synchronized (sb1) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sb1.append("A");
synchronized (sb2) {
sb2.append("B");
}
}
System.out.println(sb1);
System.out.println(sb2);
}
}.start();
new Thread(){
public void run(){
synchronized (sb2) {
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sb2.append("C");
synchronized (sb1) {
sb1.append("D");
}
}
System.out.println(sb1);
System.out.println(sb2);
}
}.start();
}
}
8、生产者消费者例子
/*
* 生产者消费者模式
* 1、是否涉及多线程;生产者、消费者
* 2、是否涉及到共享数据?有!
* 3、此共享数据是谁?即为产品数量
* 4、是否涉及到线程的通信?存在着生产者与消费者的通信
*/
class Clerk{
int produtor;
public synchronized void addProdutor(){
if(produtor>=20){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
produtor++;
System.out.println(Thread.currentThread().getName()+"生产了第:"+produtor+"个产品");
notifyAll();
}
}
public synchronized void consumeProductor(){
if(produtor<=0){
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else {
produtor--;
System.out.println(Thread.currentThread().getName()+"消费了第:"+produtor+"个产品");
notifyAll();
}
}
}
class Producer implements Runnable{
Clerk clerk;
public Producer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
System.out.println("生产者开始生产产品");
while(true){
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.addProdutor();
}
}
}
class Consumer implements Runnable{
Clerk clerk;
public Consumer(Clerk clerk) {
this.clerk = clerk;
}
@Override
public void run() {
while(true){
try {
Thread.currentThread().sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
clerk.consumeProductor();
}
}
}
public class TestProduceAndCutomer {
public static void main(String[] args) {
Clerk clerk = new Clerk();
Producer p = new Producer(clerk);
Consumer c = new Consumer(clerk);
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
Thread t3 = new Thread(p);
t1.start();
t2.start();
t3.start();
}
}
还没有评论,来说两句吧...