美文网首页Java攻城狮的入门课程@IT·互联网程序员
(四)使用synchronized实现生产者与消费者

(四)使用synchronized实现生产者与消费者

作者: 黒猫 | 来源:发表于2017-03-26 21:43 被阅读104次

    生产者有生产任务,消费者有消费任务,生产和消费可以同时进行,生产和消费的都是同一产品。

    1、搭建示例

    实现多线程同时生产并消费产品
    1.创建一个类用于存放产品的信息;
    2.类中包括生产产品和消费产品的功能;
    3.创建一个类用于存放生产任务;
    4.创建一个类用于存放消费任务;

    //描述产品
    class Product {
        private String name;
        private int count;
        private boolean flag;
    
        // 生产产品的功能
        public synchronized void produce(String name) {
            if (flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.name = count + "个" + name;
            System.out.println(Thread.currentThread().getName() + "生产了" + this.name);
            count++;
            flag = true;
            notify();
        }
    
        // 消费产品的功能
        public synchronized void consume() {
            if (!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "消费了" + this.name);
            flag = false;
            notify();
        }
    
    } 
    
    // 生产任务
    class Producer implements Runnable {
        private Product pro;
    
        public Producer(Product pro) {
            this.pro = pro;
    
        }
    
        public void run() {
            while (true) {
                pro.produce("笔记本");
            }
    
        }
    
    }
    
    // 消费任务
    class Consumer implements Runnable {
        private Product pro;
    
        public Consumer(Product pro) {
            this.pro = pro;
    
        }
    
        public void run() {
            while (true) {
                pro.consume();
            }
        }
    }
    
    public class Demo1 {
    
        public static void main(String[] args) {
            Product pro = new Product();
    
            Producer producer = new Producer(pro);
            Consumer consumer = new Consumer(pro);
    
            Thread t1 = new Thread(producer);
            Thread t2 = new Thread(consumer);
    
            t1.start();
            t2.start();
    
        }
    
    }
    
    

    此时结果如下:

    为了便于阅读文字,动画切换间隔设置的比较长。

    因为T1线程被唤醒前,flag标记已经被改为了true,假如T1线程被唤醒后能够判断flag的话,错误就可以避免,修改代码如下:

        // 生产产品的功能
        public synchronized void produce(String name) {
            // 将if改为while
            while (flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.name = count + "个" + name;
            System.out.println(Thread.currentThread().getName() + "生产了" + this.name);
            count++;
            flag = true;
            notify();
        }
    
        // 消费产品的功能
        public synchronized void consume() {
            // 将if改为while       
            while (!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "消费了" + this.name);
            flag = false;
            notify();
        }
    

    此时结果如下:

    虽然此时可以让线程返回去判断flag标记,看似解决了问题,但实际运行时却出现了线程死锁。接续接着之前的动画,分析出现死锁的原因:

    此时假设T0线程唤醒的不是T1线程,而是T2或T3线程,那么T2或T3线程判断flag标记后可正常执行消费产品,因此实际上要保证,生产线程要唤醒消费线程,消费线程要唤醒生产线程,然而notify()方法唤醒的是线程池中的任意线程,将notify()改为notifyAll()方法,虽然会牺牲程序的性能,但线程全部被唤醒,就不会出现死锁的现象了,改正所有错误的代码如下:

    //描述产品
    class Product {
        private String name;
        private int count;
        private boolean flag;
    
        // 生产产品的功能
        public synchronized void produce(String name) {
            while (flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            this.name = count + "个" + name;
            System.out.println(Thread.currentThread().getName() + "生产了" + this.name);
            count++;
            flag = true;
            notifyAll();
        }
    
        // 消费产品的功能
        public synchronized void consume() {
            while (!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "消费了" + this.name);
            flag = false;
            notifyAll();
        }
    
    } 
    
    // 生产任务
    class Producer implements Runnable {
        private Product pro;
    
        public Producer(Product pro) {
            this.pro = pro;
    
        }
    
        public void run() {
            while (true) {
                pro.produce("笔记本");
            }
    
        }
    
    }
    
    // 消费任务
    class Consumer implements Runnable {
        private Product pro;
    
        public Consumer(Product pro) {
            this.pro = pro;
    
        }
    
        public void run() {
            while (true) {
                pro.consume();
            }
        }
    }
    
    public class Demo1 {
    
        public static void main(String[] args) {
            Product pro = new Product();
            
            Producer producer = new Producer(pro);
            Consumer consumer = new Consumer(pro);
            
            Thread t0 = new Thread(producer);
            Thread t1 = new Thread(producer);
            
            Thread t2 = new Thread(consumer);
            Thread t3 = new Thread(consumer);
                    
            t0.start();
            t1.start();
            t2.start();
            t3.start();
    
        }
    
    }
    
    

    注意:
    随着JKD版本的更新,在1.5版本之后出现比synchronized更加强大的实现同步锁的方法,详情参考使用Lock接口与Condition接口实现生产者与消费者


    版权声明:欢迎转载,欢迎扩散,但转载时请标明作者以及原文出处,谢谢合作!             ↓↓↓
    

    相关文章

      网友评论

        本文标题:(四)使用synchronized实现生产者与消费者

        本文链接:https://www.haomeiwen.com/subject/yvtkottx.html