【多線程】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.啟動效果

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM