1. 程式人生 > 其它 >執行緒練習:生產者-消費者問題

執行緒練習:生產者-消費者問題

技術標籤:筆記多執行緒java

生產者-消費者問題

問題描述

生產者(Productor)將產品交給店員(Clerk),而消費者(Consumer)從店員處取走產品,店員一次只能持有固定數量的產品(比如:20),如果生產者試圖生產更多的產品,店員會叫生產者停一下,如果店中有空位放產品了再通知生產者繼續生產;如果店中沒有產品了,店員會告訴消費者等一下,如果店中有產品了再通知消費者來取走產品。

wait()/notify()/notifyall()方法

package com.java.ht;

public
class Demo1 { public static void main(String[] args) { Clerk clerk = new Clerk(); Producer p = new Producer(clerk); Consumer c = new Consumer(clerk); new Thread(p, "生產者A").start(); new Thread(p, "生產者B").start(); new Thread(c, "消費者A"
).start(); new Thread(c, "消費者B").start(); } } class Clerk{ private int product = 0; public synchronized void getProduct(){ while(product >= 20){ System.out.println("貨架已滿"); try { //如果貨架滿了,則需要讓該執行緒等待,生產者停止生產 wait
(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ":" + ++product); //賣出貨物後,需要喚醒全部執行緒,其他消費者可以繼續消費,生產者繼續生產 notifyAll(); } public synchronized void sellProduct(){ while (product <= 0){ System.out.println("貨架上缺貨"); try { //如果沒有貨物了,消費者需要等待 wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName() + ":" + --product); //消費完需要喚醒其他執行緒,生產需要生產,其他消費者消費 notifyAll(); } } class Producer implements Runnable{ private Clerk clerk; public Producer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } clerk.getProduct(); } } } class Consumer implements Runnable{ private Clerk clerk; public Consumer(Clerk clerk) { this.clerk = clerk; } @Override public void run() { for (int i = 0; i < 20; i++) { clerk.sellProduct(); } } }
  • 方法最後一定要記得喚醒執行緒
  • wait()一定要放在迴圈體裡面,不然可能會出現虛假喚醒

Lcok和Condition

package com.java.ht;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Demo2 {
    public static void main(String[] args) {
        Clerk clerk = new Clerk();
        Producer p = new Producer(clerk);
        Consumer c = new Consumer(clerk);

        new Thread(p, "生產者A").start();
        new Thread(p, "生產者B").start();
        new Thread(c, "消費者A").start();
        new Thread(c, "消費者B").start();
    }
}

class Clerk{
    private int product = 0;
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void getProduct(){
        lock.lock();
        try {
            if(product >= 20){
                //貨架已滿,停止生產
                System.out.println("貨架已滿");
                condition.await();
            } else {
                System.out.println(Thread.currentThread().getName() + ":" + ++product);
                //生產了貨物,喚醒其他執行緒
                condition.signalAll();
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void sellProduct(){
        lock.lock();
        try {
            if(product <= 0){
                //貨架上沒有貨物,需要讓消費者等待
                condition.await();
            } else {
                System.out.println(Thread.currentThread().getName() + ":" + --product);
                //消費者消費完成,喚醒其他執行緒,消費者可以繼續消費,生產者可以繼續生產
                condition.signalAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable{
    private Clerk clerk;

    public Producer1(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            clerk.getProduct();
        }
    }
}

class Consumer implements Runnable{
    private Clerk clerk;

    public Consumer1(Clerk clerk) {
        this.clerk = clerk;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            clerk.sellProduct();
        }
    }
}
  • 記得最後使用unlock()解鎖
  • Condition是Lock裡面的newCondition()產生的
  • await(),signal(),signalAll()方法和Object類中的wait(),notify(),notifyAll()一樣
  • 與上一種方法比,這種的效率更高