zoukankan      html  css  js  c++  java
  • 多线程-生产者消费者(synchronized同步)

    正解博客:https://blog.csdn.net/u011863767/article/details/59731447

    永远在循环(loop)里调用 wait 和 notify,不是在 If 语句

    现在你知道wait应该永远在被synchronized的背景下和那个被多线程共享的对象上调用,下一个一定要记住的问题就是,你应该永远在while循环,而不是if语句中调用wait。因为线程是在某些条件下等待的——在我们的例子里,即“如果缓冲区队列是满的话,那么生产者线程应该等待”,你可能直觉就会写一个if语句。但if语句存在一些微妙的小问题,导致即使条件没被满足,你的线程你也有可能被错误地唤醒。所以如果你不在线程被唤醒后再次使用while循环检查唤醒条件是否被满足,你的程序就有可能会出错——例如在缓冲区为满的时候生产者继续生成数据,或者缓冲区为空的时候消费者开始小号数据。所以记住,永远在while循环而不是if语句中使用wait!我会推荐阅读《Effective Java》,这是关于如何正确使用wait和notify的最好的参考资料。

    有的这样说:(http://www.tuicool.com/articles/a6ram23)

    因为在多核处理器环境中, Signal 唤醒操作可能会激活多于一个线程(阻塞在条件变量上的线程),使得多个调用等待的线程返回。所以用while循环对condition多次判断,可以避免这种假唤醒。

    基于以上认知,下面这个是使用wait和notify函数的规范代码模板:

    1
    2
    3
    4
    5
    6
    7
    8
    // The standard idiom for calling the wait method in Java
    synchronized(sharedObject) {
        while(condition) {
        sharedObject.wait();
            // (Releases lock, and reacquires on wakeup)
        }
        // do action based upon condition e.g. take or put into queue
    }

    就像我之前说的一样,在while循环里使用wait的目的,是在线程被唤醒的前后都持续检查条件是否被满足。如果条件并未改变,wait被调用之前notify的唤醒通知就来了,那么这个线程并不能保证被唤醒,有可能会导致死锁问题。

    注意:

    1 永远在synchronized的方法或对象里使用wait、notify和notifyAll,不然Java虚拟机会生成 IllegalMonitorStateException。

    2 永远在while循环里而不是if语句下使用wait。这样,循环会在线程睡眠前后都检查wait的条件,并在条件实际上并未改变的情况下处理唤醒通知。

    3 永远在多线程间共享的对象(在生产者消费者模型里即缓冲区队列)上使用wait。

    生产者消费者代码:

    https://zhuanlan.zhihu.com/p/20300609 代码有部分问题,修改如下

    ProsumerToConsumer类
    public class ProsumerToConsumer {
    
        public static void main(String[] args) throws Exception {
            
            Person person =new Person();
            Thread t1=new Thread(new Producer(person),"生产者t1");
            Thread t2=new Thread(new Producer(person),"生产者t2");
            Thread t3=new Thread(new Producer(person),"生产者t3");
            Thread s1=new Thread(new Consumer(person), "消费者s1");
            Thread s2=new Thread(new Consumer(person), "消费者s2");
            Thread s3=new Thread(new Consumer(person), "消费者s3");
    
            s1.start();
            s2.start();
            Thread.sleep(2000);
            t1.start();
            t2.start();
            t3.start();
                   
        }
    
    }

      producer代码:

    public class Producer implements Runnable {
    
        private Person person;
    //    private String name;
        
         public Producer( Person person) {
             this.person=person;
    //         this.name=name;
        }
         
        @Override
        public void run() {
            try {
                person.producer();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

      consumer代码:

    public class Consumer implements Runnable{
    
        private Person person;
        
         public Consumer( Person person) {
             this.person=person;
        }
    
        @Override
        public void run() {
            
            try {
                person.consumer();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

      person代码:

    public class Person {
    
        private static volatile int num=0;
        private Object obj= new Object();
        
        private static final int MAX_NUM=5;
        
        public void producer()throws InterruptedException{
            
            while(true){
                synchronized (obj) {
                    while(num==MAX_NUM) {
                        System.out.println("box is full,size = " + num);
                        obj.wait();
                    }
                    num++;
                    System.out.println( Thread.currentThread().getName()+ num);
                    obj.notifyAll();
                }
            }
        }
        
        public void consumer() throws InterruptedException{
            while (true) {
                synchronized (obj) {
                    while (num==0) {
                        System.out.println("box is empty,size = " + num);
                        obj.wait();
                    }
                    num--;
                    obj.notifyAll();
                    System.out.println(Thread.currentThread().getName() + num);
                }
            }
            }
    }

    实例验证1:如果判断用的是while  数据在队列容量范围之内。

    while(num==MAX_NUM)
            while(true){
                synchronized (obj) {
                    while(num==MAX_NUM) {
                        System.out.println("box is full,size = " + num);
                        obj.wait();
                    }

    实例验证2:如果判断用的是if  ,数据已经超出了队列的容量

    if(num==MAX_NUM) 
            while(true){
                synchronized (obj) {
                    if(num==MAX_NUM) {
                        System.out.println("box is full,size = " + num);
                        obj.wait();
                    }

  • 相关阅读:
    汇编实验程序
    javascript事件列表解说
    c#自动向网页Post信息并提取返回的信息
    C# 全半角转换
    判断 wp 是否是活跃页面
    Font Support for Windows Phone
    C# sqlite for wp7
    C#例子 易懂故事 接口 委托 事件 异步通知 好玩.
    C#用事件模式实现通知 from: http://www.cnblogs.com/guilin_gavin/archive/2011/08/18/2144397.html
    wp7 webclient 的 post 方式获取数据
  • 原文地址:https://www.cnblogs.com/Andrew520/p/8881635.html
Copyright © 2011-2022 走看看