生產者和消費者問題是線程模型中的經典問題:生產者和消費者在同一時間段內共用同一存儲空間,生產者向空間裏生產數據,而消費者從空間裏取走數據。
解決方式:要考慮線程安全的問題,解決此問題有三種方式
同步代碼塊
同步方法
lock鎖機制, 經過建立Lock對象,採用lock()加鎖,unlock()解鎖,來保護指定的代碼塊複製代碼
此文采用第二種方式解決了線程安全問題 java
wait()、nofity()這兩個方法必須有鎖對象調用,而任意對象均可以做爲 synchronized 的同步鎖,所以這三個方法只能在Object 類中聲明 。
wait():當緩衝區已滿/空時,生產者或消費者線程中止本身的執行,釋放鎖,使本身處於等待狀態,讓其它線程執行。 安全
notify():當生產者或消費者向緩衝區放入或取出一個產品時,向其餘等待的線程發出通知,同時釋放鎖,使本身處於等待狀態,讓其它線程執行。 bash
商店類(Shop):定義一個成員變量,表示第幾個麪包,提供生產麪包和消費麪包的操做;
生產者類(Producer):實現Runnable接口,重寫run()方法,調用生產麪包的操做;
消費者類(Consumer):實現Runnable接口,重寫run()方法,調用消費麪包的操做;
測試類:
/**
* 商店類(Shop):定義一個成員變量,表示第幾個麪包,提供生產麪包和消費麪包的操做;
*/
class Shop {
private int bread = 0;
/**
* 生產麪包
*/
public synchronized void produceBread() {
if (bread < 10) {
bread++;
System.out.println(Thread.currentThread().getName() + ":開始生產第" + bread + "個麪包");
notify(); // 喚醒消費者線程
} else {
try {
wait(); // 告訴生產者等待一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 消費麪包
*/
public synchronized void consumeBread() {
if (bread > 0) {
System.out.println(Thread.currentThread().getName() + ":開始消費第" + bread + "個麪包");
bread--;
notify(); // 喚醒生產者線程
} else {
try {
wait(); // 告訴消費者等待一下
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* 生產者類(Producer):實現Runnable接口,重寫run()方法,調用生產麪包的操做
*/
class Producer extends Thread {
private Shop shop;
public Producer(Shop shop) {
this.shop = shop;
}
@Override
public void run() {
System.out.println(getName() + ":開始生產麪包.....");
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
shop.produceBread();
}
}
}
/**
* 消費者類(Consumer):實現Runnable接口,重寫run()方法,調用消費麪包的操做
*/
class Consumer extends Thread {
private Shop shop;
public Consumer(Shop shop) {
this.shop = shop;
}
@Override
public void run() {
System.out.println(getName() + ":開始消費麪包.....");
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
shop.consumeBread();
}
}
}
public class BreadTest {
public static void main(String[] args) {
// 建立商店對象
Shop shop = new Shop();
// 建立生產者對象,把商店對象做爲構造方法參數傳入生產者對象中
Producer p1 = new Producer(shop);
p1.setName("生產者");
// 建立消費者對象,把商店對象做爲構造方法參數傳入消費者對象中
Consumer c1 = new Consumer(shop);
c1.setName("消費者");
p1.start();
c1.start();
}
}複製代碼
代碼執行結果以下: ide
消費者:開始消費麪包.....
生產者:開始生產麪包.....
生產者:開始生產第1個麪包
生產者:開始生產第2個麪包
生產者:開始生產第3個麪包
生產者:開始生產第4個麪包
消費者:開始消費第4個麪包
生產者:開始生產第4個麪包
生產者:開始生產第5個麪包
生產者:開始生產第6個麪包
生產者:開始生產第7個麪包
生產者:開始生產第8個麪包
消費者:開始消費第8個麪包
生產者:開始生產第8個麪包
生產者:開始生產第9個麪包
生產者:開始生產第10個麪包
消費者:開始消費第10個麪包
生產者:開始生產第10個麪包
消費者:開始消費第10個麪包
生產者:開始生產第10個麪包
消費者:開始消費第10個麪包
生產者:開始生產第10個麪包
消費者:開始消費第10個麪包
...
複製代碼
歡迎你們有興趣的能夠關注個人公衆號【java小瓜哥的分享平臺】,文章都會在裏面更新,還有各類java的資料都是免費分享的。但願與你們一塊兒進步努力!測試