線程通訊之生產者和消費者案例

使用 Object 類的 wait() 和 notify() 方法 (不適用鎖機制)

只有同步監聽對象才能夠調用 wait() 和 notify() 方法,不然報錯
線程之間進行通訊,且防止耦合度太高,使用一箇中間類做爲通訊的共同資源java

  • 須要使用 synchronized 保證一個過程的原子性
  • 使用 isEmpty 變量做爲標誌參數,在結束生產和結束消費以後改變該值
  • 使用 Object 類的 wait() 方法,判斷資源狀態,若存在則當前進程進入等待池
  • 使用 Object 類的 notify() 方法,在結束生產和結束消費以後喚醒其餘線程
  • 值得注意的是:只有同步監聽對象才能夠調用 wait() 和 notify() 方法,不然報錯

測試類

source 做爲兩個線程的參數傳入ide

public class TestDemo {
    public static void main(String[] args) {
        ShareSources source = new ShareSources();
        new Producer(source).start();
        new Comsumer(source).start();
    }
}

資源類

public class ShareSources {
    private String name;
    private String sex;
    private Boolean isEmpty = true;//使用一個參數做爲標誌

    /**
     * 存入數據
     * @param name
     * @param sex
     */
    synchronized public void push(String name, String sex) {//同步方法,保證了該方法的原子性
        try {
            //此處使用While比If更加合理,
            while (!isEmpty) {// 生產者是當前線程,若是資源任存在,則當前線程釋放鎖,進入等待池中,釋放後,消費者進程得到鎖
                this.wait();//this 指的是 source 對象 進入等待池中的線程只能被其餘線程喚醒,這裏只能在消費者線程中喚醒
            }
            //---------------------開始生產-------------------------
            this.name = name;
            Thread.sleep(10);
            this.sex = sex;
            //---------------------結束生產-------------------------
            isEmpty = false;
            this.notifyAll();//同時將其餘線程喚醒
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 獲取資源
     */
    synchronized public void get() {
        try {
            while (isEmpty) {//若是資源不存在
                this.wait();//當前線程是消費者,進入等待池
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //---------------------開始消費-------------------------
        Thread.sleep(10);       
        System.out.println(this.name + "-" + this.sex);
        //---------------------結束消費-------------------------
        isEmpty = true;
        this.notifyAll();//同時將其餘線程喚醒
    }
}

生產者類

生產者可能存在多個,且須要與消費者不一樣線程測試

public class Producer extends Thread {
    private ShareSources source = null;

    public Producer(ShareSources source) {//經過構造器獲取相同的資源
        this.source = source;
    }

    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            if (i % 2 == 0) {
                source.push("春哥", "男");
            }else {
                source.push("鳳姐", "女");
            }
        }
    }
}

消費者類

public class Comsumer extends Thread {
    private ShareSources source = null;

    public Comsumer(ShareSources source) {
        this.source = source;
    }

    public void run() {
        for (int i = 0; i < 50; i++) {
            source.get();
        }
    }
}

使用 Lock 和 condition 接口

資源類(只有該類發生變化)

須要注意的是,condition 的操做必定要在獲取鎖以後,釋放鎖以前執行,不然報錯this

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

public class ShareSources {
    private String name;
    private String sex;
    private Boolean isEmpty = true;
    // 實例化鎖
    private final Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();// 因爲Condition是一個接口,lock.newCondition()方法返回一個綁定的Condition實例

    /**
     * 存入數據
     * 
     * @param name
     * @param sex
     */
    public void push(String name, String sex) {
        lock.lock();
        try {
            if (!isEmpty) {
                condition.await();// 使用condition的await()方法至關於 Object 類的 wait 方法
            }
            this.name = name;
            Thread.sleep(10);
            this.sex = sex;
            isEmpty = false;
            condition.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 獲取資源
     */
    public void get() {
        lock.lock();
        try {
            if (isEmpty) {
                condition.await();// 使用condition的await()方法至關於 Object 類的 wait 方法
            }
            Thread.sleep(10);
            System.out.println(this.name + "-" + this.sex);
            isEmpty = true;
            condition.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
相關文章
相關標籤/搜索