线程间的通信机制(等待和唤醒机制)

线程之间为什么需要进行通信?

       我们都知道,要想能够去执行一个线程,首先这个线程需要获取CPU的执行权,当这个线程执行完毕之后,就会释放CPU资源,并发执行的时候,剩下的处于就绪状态的线程就会一起去争夺CPU的执行权,谁抢到谁就执行。但是在开发过程中,我们可能需要多个线程进行协调配合来完成一件事。也就是说,我们需要线程之间有规律的去执行任务。这就需要线程之间相互通信了。

       当多个线程共同去争夺同一个cpu资源的时候,只能有一个线程能够抢到,其他没抢到的就会进入阻塞状态,等待抢到cpu资源的线程执行结束再去抢夺。通过一个简单的例子说明一下。包子店老板A将包子生产好之后,就叫顾客B过来吃。这个小案例中,就提现了类似线程中等待与唤醒机制。 

    A先生产,此时B在等待A生产好。

    A生产好之后,通知B来吃,相当于B被A唤醒。

线程之间的通信依靠的是wait()notify()notifyAll()方法进行协调。这三个方法都是定义在了Object类中

等待与唤醒方法基本概念:

wait():
  当线程A调用wait()方法后,释放同步锁,进入阻塞状态,然后加入到等待锁对象的队列中。
notify():
  线程B获取到同步锁之后,调用notify()方法,从等待锁的队列中唤醒一个线程(被唤醒的线程状态由等待转变成就绪,等线程B执行完毕释放了锁资源之后,被唤醒的线程获取到锁之后就会去执行该线程)
notifyAll():
  线程B获取到同步锁之后,调用notifyAll()方法,会唤醒等待锁队列中所有的线程,等待线程B执行完之后释放锁资源,被唤醒的线程去争夺锁资源,获取到锁对象的线程会去执行相应的逻辑。

使用wait和notify方法时,需要注意这些细节:

       wait方法与notify方法必须要由同一个锁对象调用。对应的锁对象可以通过notify唤醒使用同一个锁对象调用的wait方法线程。

       wait方法与notify方法是属于Object类的方法,锁对象可以是任意对象,而任意对象的所属类都是继承Object类的。

       wait方法与notify方法必须要在同步代码块或者同步函数中使用,必须通过锁对象调用这两个方法。关于线程间的通信和等待唤醒机制,其实,两者没有很大的区别,总结成一句话,线程之间的分工合作,即哪个线程,什么时候该等待。哪个线程,什么时候该执行,以保证资源的有效利用。

练习:生产者和消费者案例

包子代码:

public class BaoZi {
    String name;//包子的名称

    Boolean flag;//包子的状态(true表示存在  false 表示不存在)
}

吃货代码:

public class ChiHuo extends Thread{
    BaoZi baoZi;

    //构造函数:用来指定线程的名称和操作资源
    public ChiHuo(String name,BaoZi baoZi){
        super(name);
        this.baoZi=baoZi;
    }
    public void run(){
        String threadName=Thread.currentThread().getName();
        int count=0;
        while(true){
            synchronized (baoZi){
                count++;
                if (count>10){
                    break;
                }
                if(baoZi.flag){//如果包子存在
                    System.out.println(threadName+"开始吃"+baoZi.name);
                    baoZi.flag=false;//修改状态
                    baoZi.notify();//唤醒其他资源状态
                }else{
                    //如果包子不存在
                    try {
                        baoZi.wait();//进入等待状态
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

包子店代码:

public class ZaoCanDian extends Thread{
    BaoZi baoZi;

    //构造函数:用来指定线程的名称和操作资源
    public ZaoCanDian(String name, BaoZi baoZi) {
        super(name);
        this.baoZi = baoZi;
    }

    public void run() {
        String threadName = Thread.currentThread().getName();
        int count = 0;
        while (true) {
            synchronized (baoZi) {
                count++;
                if (count > 10) {
                    break;
                }
                if (baoZi.flag) {//如果包子存在
                    try {
                        baoZi.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } else {
                    //如果包子不存在
                    System.out.println(threadName + "开始制作" + baoZi.name);
                    baoZi.flag=true;//更改包子状态
                    baoZi.notify();//唤醒同一资源下的其他线程
                }
            }
        }
    }
}

测试类:

public class ThreadTest {
    public static void main(String[] args) {
        //定义资源对象
        BaoZi baoZi=new BaoZi();
        baoZi.name="韭菜鸡蛋";
        baoZi.flag=true;

        //定义两个线程,起名字且操作同一对象
        ChiHuo ch=new ChiHuo("猪八戒",baoZi);
        ZaoCanDian zcd=new ZaoCanDian("春光早餐",baoZi);

        //启动线程
        zcd.start();
        ch.start();
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值