常用的同步方法是采用信號(hào)或加鎖機(jī)制,確保資源在任意時(shí)刻至多被一個(gè)線程訪問。Java語言在多線程編程上實(shí)現(xiàn)了完全對(duì)象化,提供了對(duì)同步機(jī)制的良好支持。
在Java中一共有四種方法支持同步,其中前三個(gè)是同步方法,一個(gè)是管道方法。管道方法不建議使用,阻塞隊(duì)列方法在問題4已有描述,現(xiàn)只提供前兩種實(shí)現(xiàn)方法。
- wait()/notify()方法
- await()/signal()方法
- BlockingQueue阻塞隊(duì)列方法
- PipedInputStream/PipedOutputStream
一、生產(chǎn)者類:
```
public class Producer extends Thread { // 每次生產(chǎn)的產(chǎn)品數(shù)量
private int num;
// 所在放置的倉庫
private Storage storage;
// 構(gòu)造函數(shù),設(shè)置倉庫
public Producer(Storage storage) {
this.storage = storage;
}
// 線程run函數(shù)
public void run() {
produce(num);
}
// 調(diào)用倉庫Storage的生產(chǎn)函數(shù)
public void produce(int num) {
storage.produce(num);
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public Storage getStorage() {
return storage;
}
public void setStorage(Storage storage) {
this.storage = storage;
}
}
```
二、消費(fèi)者類:
```
public class Consumer extends Thread { // 每次消費(fèi)的產(chǎn)品數(shù)量
private int num;
// 所在放置的倉庫
private Storage storage;
// 構(gòu)造函數(shù),設(shè)置倉庫
public Consumer(Storage storage) {
this.storage = storage;
}
// 線程run函數(shù)
public void run() {
consume(num);
}
// 調(diào)用倉庫Storage的生產(chǎn)函數(shù)
public void consume(int num) {
storage.consume(num);
}
// get/set方法
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public Storage getStorage() {
return storage;
}
public void setStorage(Storage storage) {
this.storage = storage;
}
}
```
倉庫類:(wait()/notify()方法)
```
public class Storage { // 倉庫最大存儲(chǔ)量
private final int MAX_SIZE = 100;
// 倉庫存儲(chǔ)的載體
private LinkedList list = new LinkedList();
// 生產(chǎn)num個(gè)產(chǎn)品
public void produce(int num) {
// 同步代碼段
synchronized (list) {
// 如果倉庫剩余容量不足
while (list.size() + num > MAX_SIZE) {
System.out.print("【要生產(chǎn)的產(chǎn)品數(shù)量】:" + num);
System.out.println(" 【庫存量】:" + list.size() + " 暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!");
try {
list.wait();// 由于條件不滿足,生產(chǎn)阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生產(chǎn)條件滿足情況下,生產(chǎn)num個(gè)產(chǎn)品
for (int i = 1; i <= num; ++i) {
list.add(new Object());
}
System.out.print("【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:" + num);
System.out.println(" 【現(xiàn)倉儲(chǔ)量為】:" + list.size());
list.notifyAll();
}
}
// 消費(fèi)num個(gè)產(chǎn)品
public void consume(int num) {
// 同步代碼段
synchronized (list) {
// 如果倉庫存儲(chǔ)量不足
while (list.size() < num) {
System.out.print("【要消費(fèi)的產(chǎn)品數(shù)量】:" + num);
System.out.println(" 【庫存量】:" + list.size() + " 暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!");
try {
// 由于條件不滿足,消費(fèi)阻塞
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消費(fèi)條件滿足情況下,消費(fèi)num個(gè)產(chǎn)品
for (int i = 1; i <= num; ++i) {
list.remove();
}
System.out.print("【已經(jīng)消費(fèi)產(chǎn)品數(shù)】:" + num);
System.out.println(" 【現(xiàn)倉儲(chǔ))量為】:" + list.size());
list.notifyAll();
}
}
// get/set方法
public LinkedList getList() {
return list;
}
public void setList(LinkedList list) {
this.list = list;
}
public int getMAX_SIZE() {
return MAX_SIZE;
}
}
```
倉庫類:(await()/signal()方法)
```
public class Storage { // 倉庫最大存儲(chǔ)量
// 倉庫最大存儲(chǔ)量
private final int MAX_SIZE = 100;
// 倉庫存儲(chǔ)的載體
private LinkedList list = new LinkedList();
// 鎖
private final Lock lock = new ReentrantLock();
// 倉庫滿的條件變量
private final Condition full = lock.newCondition();
// 倉庫空的條件變量
private final Condition empty = lock.newCondition();
// 生產(chǎn)num個(gè)產(chǎn)品
public void produce(int num) {
// 獲得鎖
lock.lock();
// 如果倉庫剩余容量不足
while (list.size() + num > MAX_SIZE) {
System.out.print("【要生產(chǎn)的產(chǎn)品數(shù)量】:" + num);
System.out.println(" 【庫存量】:" + list.size() + " 暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!");
try {
// 由于條件不滿足,生產(chǎn)阻塞
full.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 生產(chǎn)條件滿足情況下,生產(chǎn)num個(gè)產(chǎn)品
for (int i = 1; i <= num; ++i) {
list.add(new Object());
}
System.out.print("【已經(jīng)生產(chǎn)產(chǎn)品數(shù)】:" + num);
System.out.println(" 【現(xiàn)倉儲(chǔ)量為】:" + list.size());
// 喚醒其他所有線程
full.signalAll();
empty.signalAll();
// 釋放鎖
lock.unlock();
}
// 消費(fèi)num個(gè)產(chǎn)品
public void consume(int num) {
// 獲得鎖
lock.lock();
// 如果倉庫存儲(chǔ)量不足
while (list.size() < num) {
System.out.print("【要消費(fèi)的產(chǎn)品數(shù)量】:" + num);
System.out.println(" 【庫存量】:" + list.size() + " 暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)!");
try {
// 由于條件不滿足,消費(fèi)阻塞
empty.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 消費(fèi)條件滿足情況下,消費(fèi)num個(gè)產(chǎn)品
for (int i = 1; i <= num; ++i) {
list.remove();
}
System.out.print("【已經(jīng)消費(fèi)產(chǎn)品數(shù)】:" + num);
System.out.println(" 【現(xiàn)倉儲(chǔ))量為】:" + list.size());
// 喚醒其他所有線程
full.signalAll();
empty.signalAll();
// 釋放鎖
lock.unlock();
}
// set/get方法
public int getMAX_SIZE() {
return MAX_SIZE;
}
public LinkedList getList() {
return list;
}
public void setList(LinkedList list) {
this.list = list;
}
}