1. 程式人生 > 其它 >java實現<生產者-消費者>的兩種方式

java實現<生產者-消費者>的兩種方式

技術標籤:Java

1,兩種方式簡單介紹:

1.1 使用Synchronized關鍵字

Synchronized + wait() + notifyAll()

注意點:

判斷條件用while迴圈,如果用if會出現虛假喚醒。

1.2使用Lock介面

ReentrantLock + Condition + await() + singsignalAll()

注意點:

Lock lock = new ReentrantLock(); //注意Lock 的實現類
Condition condition = lock.newCondition(); //注意Condition通過lock獲取

2,使用synchronized

直接上程式碼:

/**
 * 資源類
 * @author dangkaimin
 */
public class Source {
    private int number = 0; //資源
    /* 生產 */
    public synchronized void push() {
        while(number == 1){  //判斷 注意判斷條件用while,如果用if會出現虛假喚醒
            this.wait();     //等待
        }	
        number = 1;			 //業務
        System.
out.println(Thread.currentThread().getName() + "push number = " + number); this.notifyAll(); //通知 } /* 消費 */ public synchronized void pop() { while(number == 0){ //判斷 this.wait(); //等待 } number = 0; //業務 System.out.println
(Thread.currentThread().getName() + "pop number = " + number); this.notifyAll(); //通知 } public static void main(String[] args){ Source source = new Source(); /* 生產者*/ new Thread( () -> { while(true) { source.push(); } }).start(); /* 消費者*/ new Thread( () -> { while(true) { source.pop(); } }).start(); }

3,使用Lock介面

/**
 * 資源類
 * @author dangkaimin
 */
public class Source {
    private int number = 0; //資源
    private Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    /* 生產 */
    public void push() {
        lock.lock();
        try {
            while(number == 1){ 	//判斷
	            condition.await();	//等待
            }
            number = 1;				//業務
            System.out.println(Thread.currentThread().getName() + " push number = " + number);
            condition.signalAll();   //通知
        }finally {
            lock.unlock();
        }
    }
    /* 消費 */
    public void pop() {
        lock.lock();
        try {
            while(number == 0){		//判斷
                condition.await();	//等待
            }
            number = 0;				//業務
            System.out.println(Thread.currentThread().getName() + " pop number = " + number);
            condition.signalAll();   //通知
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args){
        Source source = new Source();
        /* 生產者*/
        new Thread( () -> {
            while(true) {
                source.push();
            }
        },"A").start();

        /* 消費者*/
        new Thread( () -> {
            while(true) {
                source.pop();
            }
        },"B").start();
    }
}

3,Lock升級版:通過condition實現執行緒的精準通知。

流程:A喚醒B,B喚醒C,C喚醒A

注意點:

  • 使用一個鎖的不同condition
  • 注意判斷條件的合理。
/**
 * 資源類
 * @author dangkaimin
 */
public class Source {
    private int number = 1; //資源
    private Lock lock = new ReentrantLock();
    Condition condition_A = lock.newCondition();
    Condition condition_B = lock.newCondition();
    Condition condition_C = lock.newCondition();

    public void method_A() {
        lock.lock();
        try {
            while(number != 1){  //判斷
                condition_A.await();   //等待
            }
            number = 2;
            System.out.println(Thread.currentThread().getName() + " A number = " + number);
            condition_B.signal();   //喚醒A
        }catch(Exception e){

        }finally {
            lock.unlock();
        }
    }
    /* 消費 */
    public void method_B() {
        lock.lock();
        try {
            while(number != 2){     //判斷
                condition_B.await();   //等待
            }
            number = 3;
            System.out.println(Thread.currentThread().getName() + " B number = " + number);
            condition_C.signal();   //喚醒B
        }catch(Exception e){

        } finally {
            lock.unlock();
        }
    }
    public void method_C() {
        lock.lock();
        try {
            while(number != 3){     //判斷
                condition_C.await();   //等待
            }
            number = 1;
            System.out.println(Thread.currentThread().getName() + " C number = " + number);
            condition_A.signal();   //喚醒A
        }catch(Exception e){

        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args){
        Source source = new Source();
        new Thread( () -> {
            while(true) {
                source.method_A();
            }
        },"method_A").start();

        new Thread( () -> {
            while(true) {
                source.method_B();
            }
        },"method_B").start();
        new Thread( () -> {
            while(true) {
                source.method_C();
            }
        },"method_C").start();
    }
}

精準通知結果如下:

method_C C number = 1
method_A A number = 2
method_B B number = 3
method_C C number = 1
method_A A number = 2
method_B B number = 3
method_C C number = 1
method_A A number = 2
method_B B number = 3
...