synchronized wait notify 生产者消费者

Posted jqka

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了synchronized wait notify 生产者消费者相关的知识,希望对你有一定的参考价值。

1.生产者消费者模型

public class ProducterConsumerTest{
    public static void main(String[] args){
        System.out.println("this is a test...");
        Message msg=new Message();
        Producter pro=new Producter(msg);
        Consumer con=new Consumer(msg);
        new Thread(pro).start();
        new Thread(con).start();
        new Thread(con).start();
    }
}
class Message {
    String title;
    String content;

    public synchronized void set(String title,String content){
        //问题1:while 还是 if
        while (this.content!=null){
            try{
                this.wait();
            }catch(Exception exc){}
        }
        //模拟延迟
        try{
            Thread.sleep(100);
        }catch(Exception exc){}
        this.title=title;
        this.content=content;
        System.out.println(Thread.currentThread().getName()+"-生产:"+this.title+this.content);
        //问题2 notify 还是notifyAll
        super.notify();
    }
    public synchronized void get(){
        //问题1:while 还是 if
        while(this.content==null){
            try{
                this.wait();
            }catch(Exception exc){}
        }
        //模拟延迟
        try{
            Thread.sleep(100);
        }catch(Exception exc){}
        System.out.println(Thread.currentThread().getName()+"-消费:"+this.title+this.content);
        this.title=null;
        this.content=null;
        //问题2 notify 还是notifyAll
        super.notify();
    }
}
class Producter implements Runnable {
    Message msg;
    public Producter(Message msg){
        this.msg=msg;
    }
    @Override
    public void run(){

        for(int i=0;i<10;i++){

            msg.set("华为"," Meate100");
        }
    }
}
class Consumer implements Runnable{
    Message msg;
    public Consumer(Message msg){
        this.msg=msg;
    }
    @Override
    public void run(){
        for(int i=0;i<5;i++){
            msg.get();
        }
    }
}

//运行结果(notifyAll()+while):
this is a test...
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100
生产:华为 Meate100
消费:华为 Meate100

2.Entry Set(锁池)、Wait Set(等待池)

对于Entry Set:如果线程A已经持有了对象锁,此时有其他线程也想获得该对象锁的话,它只能进入Entry Set,并且线程处于BLOCKED状态。

对于Wait Set:如果线程A调用了wait()方法,那么线程A会释放该对象的锁,进入到Wait Set,并且线程处于WAITING状态。

3.Wait、Notify、NotifyAll 、Entry Set(锁池)、Wait Set(等待池)画图说明

技术图片        技术图片        技术图片


技术图片        技术图片        技术图片


技术图片        技术图片        技术图片

4.衍生出的问题

A.用notify还是notifyAll:
线程1-生产
线程2-消费 -waiting
线程3-消费 -waiting
notify场景分析:
步骤一:线程1生产完成后wait(),执行notify()随机唤醒一个是线程2,判断之后满足条件,进行消费,线程2消费完后wait(),执行notify().
此时三个线程状态是
线程1-waiting
线程2-waiting-执行notify
线程3-waiting

步骤二:这是如果唤醒的是线程3,那么是不满足消费条件的,所以线程3继续wait(),而没有进行唤醒操作
这是问题产生了
线程1-waiting
线程2-waiting
线程3-waiting
死锁、死锁、死锁了...
技术图片

如果我们用的是notifyAll(),那么步骤一线程2消费完成后,执行notifyAll(),结果是什么呢?
(1)如果是线程1抢到锁,满足条件,进行生产,生产完成后notifyAll()
(2)如果是线程3抢到锁,不满足条件,线程3wait(),释放锁,此时只有线程1是在锁池中,线程1会抢到锁,之后执行(1)

so,notify会导致死锁问题,最好使用notifyAll()

B.wait外层用while还是if:
notifyAll下if运行结果:
技术图片

这里我没想明白,明明是同步方法为啥子会出现这个问题呢?
或者
就是当线程被wait之后进入等待队列,当被唤醒时,线程是继续往wait下面继续执行还是从synchronized monitor锁的地方再次执行?

答案只有一个:
上边的异常说明了->【wait被唤醒后,会继续往wait之后的代码执行而不是重新从monitor同步块处执行】 (这个结论是从代码运行推断,能力有限,没找到佐证,留待后续补充吧...........)
附上JDK中的说明
技术图片

C.wait和synchronized绑定使用:
同上图

以上是关于synchronized wait notify 生产者消费者的主要内容,如果未能解决你的问题,请参考以下文章

为什么wait和notify只能在synchronized中?

wait()和notify()

wait() notify()搭配synchronize的使用

synchronized wait notify 生产者消费者

面试官:为什么 wait/notify 必须与 synchronized 一起使用??

synchronized VS Lock, wait-notify VS Condition