zoukankan      html  css  js  c++  java
  • 【多线程】java多线程实现生产者消费者模式 synchronized+Object的wait/notify方式 和 Lock+Condition的await/signal方式

    =========================使用synchronized,配合Object的wait()/notify()实现生产者消费者======================

     思考问题:

    1.为什么用wait()+notify()实现生产者消费者模式?

    wait()方法可以暂停线程,并释放对象锁
    notify()方法可以唤醒需要该对象锁的其他线程,并在执行完后续步骤,到了synchronized临界区后,才会把锁释放

    2.为什么wait()、notify()、notifyAll()方法需要放在同步代码块中执行?

    wait()方法暂停线程执行,并立即释放对象锁
    
    notify()/notifyAll() 方法唤醒其他等待该对象锁的线程,并在执行完同步代码块中的后续步骤后,释放对象锁
    
    notify()和notifyAll()的区别在于:
        notify只会唤醒其中一个线程,
        notifyAll则会唤醒全部线程。
        
    至于notify会唤醒哪个线程,是由线程调度器决定的。
    因为这三个方法都需要获取到对象锁才能有效执行。否则就会抛异常:java.lang.IllegalMonitorStateException

    3.wait()是暂停的哪个线程?notify()唤醒的是哪个线程?

    wait()是暂停当前线程。
    
    notify()则是唤醒等待当前对象锁的线程

    4.什么是生产者消费者模式

    一个产数据,一个用数据,中间最多再加上个存取仓库
    生产者消费者模式 就是java多线程通信一个很好的例子

    5.生产着消费者模式特点是什么

    1.解耦,生产者干生产者的事情,消费者干消费者的事情
    
    2.支持高并发,可以同时多个生成,多个消费,互不影响

    6.一对一的生产者消费者模式:

      1>早餐类:

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    /**
     * 早餐基础类
     *
     * wait()
     * notify()
     * notifyAll()
     * 三个方法 需要放在同步代码块中执行 因为要获取对象锁
     */
    public class Breakfast{
        private  String food;
    
        private  String drink;
    
        private boolean flag = false;//flag = false 表示需要生产  flag = true 表示需要消费
    
        public synchronized  void  makeBreakfast(String food,String drink){
    
            System.out.println("生产者进入--->标志值为:"+flag);
            if (flag){
                try {
                    System.out.println("make---wait()暂停,释放对象锁");
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            this.food = food;
            try {
                System.out.println("make---sleep()休眠,不释放对象锁");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            this.drink = drink;
            System.out.println("make---生产者制造东西完成----");
            this.flag = true;
            System.out.println("make---notify()唤醒,标志值为"+flag);
            notify();
        }
    
    
        public synchronized void eatBreakfast(){
    
            System.out.println("消费者进入--->标志值为:"+flag);
            if(!flag){
                try {
                    System.out.println("eat---wait()");
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    
            try {
                System.out.println("eat---sleep()");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("吃东西---"+this.food+";喝东西---"+this.drink);
            this.flag = false;
            System.out.println("eat---notify()唤醒,标志值为"+flag);
            notify();
        }
    }
    View Code

      2> 生产者类:

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    public class Producer implements Runnable{
    
        private Breakfast breakfast;
    
        public Producer(Breakfast breakfast) {
            this.breakfast = breakfast;
        }
    
        @Override
        public void run() {
            int i = 7;
            for (int i1 = 0; i1 < i; i1++) {
                if (i1 %2 == 0){
                    this.breakfast.makeBreakfast("馒头","豆浆");
                }else {
                    this.breakfast.makeBreakfast("面包","冷饮");
                }
            }
        }
    }
    View Code

      3>消费者类:

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    public class Consumer implements Runnable{
    
        private Breakfast breakfast;
    
        public Consumer(Breakfast breakfast) {
            this.breakfast = breakfast;
        }
    
        @Override
        public void run() {
            int i = 7;
            for (int i1 = 0; i1 < i; i1++) {
                System.out.println("星期"+(i1+1)+"---消费者要来吃东西了");
                this.breakfast.eatBreakfast();
            }
        }
    }
    View Code

      4>线程启动主测试类:

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    public class Test {
    
        public static void main(String[] args) {
            Breakfast breakfast = new Breakfast();
            new Thread(new Producer(breakfast)).start();
            new Thread(new Consumer(breakfast)).start();
        }
    }
    View Code

      5>展示结果:

    ===========================使用Lock,配合Condition的await()/signal()实现生产者消费者============================

     1.早饭类,提供生产方法和消费方法

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    import java.util.LinkedList;
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     *
     * Lock配合condition实现生产者消费者模式
     *
     * @author sxd
     * @date 2019/8/6 9:08
     */
    public class Condition_Breakfast {
    
        private LinkedList<String> breakfastList;//早饭资源容器
    
        private int maxSize;//最大量早饭资源数量 自定义
    
        private Lock lock; //
    
        private Condition comsumerCondition;//满条件【即代表消费者等待队列】
    
        private Condition producerCondition;//不满条件【即代表生产者等待队列】
    
    
        //自定义 最大共享资源数量
        public Condition_Breakfast(int maxSize) {
            this.maxSize = maxSize;
            breakfastList = new LinkedList<>();
            lock = new ReentrantLock();
            comsumerCondition = lock.newCondition();
            producerCondition = lock.newCondition();
        }
    
    
        public void produce(String str){
            lock.lock();
            try {
                while (maxSize == breakfastList.size()){
                    System.out.println("如果早餐共享资源已经满足最大量,则进入本方法的当前线程们,进入notFullCondition的等待队列中,线程挂起");
                    producerCondition.await();
                }
    
                breakfastList.add(str);
                System.out.println("生产早饭:"+str);
    
                System.out.println("早饭已经被生产了,唤醒消费者等待队列中的线程,可以继续开始消费了");
                comsumerCondition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        }
    
    
        public String consume(){
            String str = null;
            lock.lock();
    
            try {
                while (breakfastList.size() == 0 ){
                    System.out.println("如果早饭共享资源完全==0,就将消费者们挂起,等待生产者生产后再去唤醒消费者们");
                    comsumerCondition.await();
                }
    
                str = breakfastList.poll();
                System.out.println("消费早饭:"+str);
    
                System.out.println("早饭已经被消费了,唤醒生产者等待队列中的 线程,可以继续生产了");
                producerCondition.signal();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
    
            return str;
        }
    
    
    
    }
    View Code

    2.早饭类的生产者

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    /**
     * @author sxd
     * @date 2019/8/6 9:26
     */
    public class Condition_Producer implements Runnable {
    
        Condition_Breakfast breakfast;
    
        public Condition_Producer(Condition_Breakfast breakfast) {
            this.breakfast = breakfast;
        }
    
    
        @Override
        public void run() {
            int i = 7;
            String threadName = Thread.currentThread().getName();
            for (int i1 = 0; i1 < i; i1++) {
                if (i1 %2 == 0){
                    this.breakfast.produce(threadName+"大馒头"+i1);
                }else {
                    this.breakfast.produce(threadName+"大包子"+i1);
                }
            }
        }
    }
    View Code

    3.早饭类的消费者

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    /**
     * @author sxd
     * @date 2019/8/6 9:28
     */
    public class Condition_Comsumer implements Runnable{
    
        Condition_Breakfast breakfast;
    
        public Condition_Comsumer(Condition_Breakfast breakfast) {
            this.breakfast = breakfast;
        }
    
    
        @Override
        public void run() {
            int i = 7;
            for (int i1 = 0; i1 < i; i1++) {
                this.breakfast.consume();
            }
        }
    }
    View Code

    4.测试类

    package com.sxd.swapping.test.ProducerAndConsumerTest;
    
    /**
     * @author sxd
     * @date 2019/8/6 9:30
     */
    public class Test2 {
    
        public static void main(String[] args) {
            Condition_Breakfast breakfast = new Condition_Breakfast(16);
            new Thread(new Condition_Producer(breakfast)).start();
            new Thread(new Condition_Producer(breakfast)).start();
            new Thread(new Condition_Producer(breakfast)).start();
            new Thread(new Condition_Comsumer(breakfast)).start();
            new Thread(new Condition_Comsumer(breakfast)).start();
            new Thread(new Condition_Comsumer(breakfast)).start();
    
        }
    
    
    
    }
    View Code

    5.启动效果

  • 相关阅读:
    WPF 之 布局(一)
    CSS 之 内层div填充margin,外层div的背景色不会覆盖该margin
    T-SQL 之 多表联合更新
    jQuery
    Joomla, Wordpress, Drupal 全面详细Pk比较-转载
    js ==与===区别(两个等号与三个等号)
    Jquery DataTables 自定义布局sdom
    Jquery DataTable
    解决Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in
    firedebug调试Jquery
  • 原文地址:https://www.cnblogs.com/sxdcgaq8080/p/10654201.html
Copyright © 2011-2022 走看看