【多线程】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.启动效果

 

posted @ 2019-04-04 12:45  Angel挤一挤  阅读(2250)  评论(0编辑  收藏  举报