好程式設計師分享同一資源多執行緒併發訪問時的完整性

好程式設計師IT發表於2019-09-29

   好程式設計師面試題分享 同一資源多執行緒併發訪問時的完整性 常用的同步方法是採用訊號或加鎖機制,確保資源在任意時刻至多被一個執行緒訪問。Java 語言在多執行緒程式設計上實現了完全物件化,提供了對同步機制的良好支援。

 

  在Java 中一共有四種方法支援同步,其中前三個是同步方法,一個是管道方法。管道方法不建議使用,阻塞佇列方法在問題 4 已有描述,現只提供前兩種實現方法。

 

  - wait()/notify() 方法

 

  - await()/signal() 方法

 

  - BlockingQueue 阻塞佇列方法

 

  - PipedInputStream/PipedOutputStream

 

  一、生產者類:

 

  ```

 

  public class Producer extends Thread { // 每次生產的產品數量

 

  private int num;

 

  // 所在放置的倉庫

 

  private Storage storage;

 

  // 建構函式,設定倉庫

 

  public Producer(Storage storage) {

 

  this.storage = storage;

 

  }

 

  // 執行緒 run 函式

 

  public void run() {

 

  produce(num);

 

  }

 

  // 呼叫倉庫 Storage 的生產函式

 

  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;

 

  }

 

  }

 

  ```

 

  二、消費者類:

 

  ```

 

  public class Consumer extends Thread { // 每次消費的產品數量

 

  private int num;

 

  // 所在放置的倉庫

 

  private Storage storage;

 

  // 建構函式,設定倉庫

 

  public Consumer(Storage storage) {

 

  this.storage = storage;

 

  }

 

  // 執行緒 run 函式

 

  public void run() {

 

  consume(num);

 

  }

 

  // 呼叫倉庫 Storage 的生產函式

 

  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 { // 倉庫最大儲存量

 

  private final int MAX_SIZE = 100;

 

  // 倉庫儲存的載體

 

  private LinkedList list = new LinkedList();

 

  // 生產 num 個產品

 

  public void produce(int num) {

 

  // 同步程式碼段

 

  synchronized (list) {

 

  // 如果倉庫剩餘容量不足

 

  while (list.size() + num > MAX_SIZE) {

 

  System.out.print(" 【要生產的產品數量】 :" + num);

 

  System.out.println(" 【庫存量】 :" + list.size() + " 暫時不能執行生產任務 !");

 

  try {

 

  list.wait();// 由於條件不滿足,生產阻塞

 

  } catch (InterruptedException e) {

 

  e.printStackTrace();

 

  }

 

  }

 

  // 生產條件滿足情況下,生產 num 個產品

 

  for (int i = 1; i <= num; ++i) {

 

  list.add(new Object());

 

  }

 

  System.out.print(" 【已經生產產品數】 :" + num);

 

  System.out.println(" 【現倉儲量為】 :" + list.size());

 

  list.notifyAll();

 

  }

 

  }

 

  // 消費 num 個產品

 

  public void consume(int num) {

 

  // 同步程式碼段

 

  synchronized (list) {

 

  // 如果倉庫儲存量不足

 

  while (list.size() < num) {

 

  System.out.print(" 【要消費的產品數量】 :" + num);

 

  System.out.println(" 【庫存量】 :" + list.size() + " 暫時不能執行生產任務 !");

 

  try {

 

  // 由於條件不滿足,消費阻塞

 

  list.wait();

 

  } catch (InterruptedException e) {

 

  e.printStackTrace();

 

  }

 

  }

 

  // 消費條件滿足情況下,消費 num 個產品

 

  for (int i = 1; i <= num; ++i) {

 

  list.remove();

 

  }

 

  System.out.print(" 【已經消費產品數】 :" + num);

 

  System.out.println(" 【現倉儲 ) 量為】 :" + 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 { // 倉庫最大儲存量

 

  // 倉庫最大儲存量

 

  private final int MAX_SIZE = 100;

 

  // 倉庫儲存的載體

 

  private LinkedList list = new LinkedList();

 

  //

 

  private final Lock lock = new ReentrantLock();

 

  // 倉庫滿的條件變數

 

  private final Condition full = lock.newCondition();

 

  // 倉庫空的條件變數

 

  private final Condition empty = lock.newCondition();

 

  // 生產 num 個產品

 

  public void produce(int num) {

 

  // 獲得鎖

 

  lock.lock();

 

  // 如果倉庫剩餘容量不足

 

  while (list.size() + num > MAX_SIZE) {

 

  System.out.print(" 【要生產的產品數量】 :" + num);

 

  System.out.println(" 【庫存量】 :" + list.size() + " 暫時不能執行生產任務 !");

 

  try {

 

  // 由於條件不滿足,生產阻塞

 

  full.await();

 

  } catch (InterruptedException e) {

 

  e.printStackTrace();

 

  }

 

  }

 

  // 生產條件滿足情況下,生產 num 個產品

 

  for (int i = 1; i <= num; ++i) {

 

  list.add(new Object());

 

  }

 

  System.out.print(" 【已經生產產品數】 :" + num);

 

  System.out.println(" 【現倉儲量為】 :" + list.size());

 

  // 喚醒其他所有執行緒

 

  full.signalAll();

 

  empty.signalAll();

 

  // 釋放鎖

 

  lock.unlock();

 

  }

 

  // 消費 num 個產品

 

  public void consume(int num) {

 

  // 獲得鎖

 

  lock.lock();

 

  // 如果倉庫儲存量不足

 

  while (list.size() < num) {

 

  System.out.print(" 【要消費的產品數量】 :" + num);

 

  System.out.println(" 【庫存量】 :" + list.size() + " 暫時不能執行生產任務 !");

 

  try {

 

  // 由於條件不滿足,消費阻塞

 

  empty.await();

 

  } catch (InterruptedException e) {

 

  e.printStackTrace();

 

  }

 

  }

 

  // 消費條件滿足情況下,消費 num 個產品

 

  for (int i = 1; i <= num; ++i) {

 

  list.remove();

 

  }

 

  System.out.print(" 【已經消費產品數】 :" + num);

 

  System.out.println(" 【現倉儲 ) 量為】 :" + 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;

 

  }

 

  }

 

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69913892/viewspace-2658724/,如需轉載,請註明出處,否則將追究法律責任。

相關文章