Java技術學習:如何保證同一資源被多個線程併發訪問時的完整性?

常用的同步方法是採用信號或加鎖機制,保證資源在任意時刻至多被一個線程訪問。Java語言在多線程編程上實現了完全對象化,提供了對同步機制的良好支持。

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

- 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<Object> list = new LinkedList<Object>();

    // 生產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<Object> getList() {

         return list;

    }

    public void setList(LinkedList<Object> list) {

         this.list = list;

    }

    public int getMAX_SIZE() {

         return MAX_SIZE;

    }

}

```

倉庫類:(await()/signal()方法)

```

public class Storage { // 倉庫最大存儲量

    // 倉庫最大存儲量

    private final int MAX_SIZE = 100;

    // 倉庫存儲的載體

    private LinkedList<Object> list = new LinkedList<Object>();

    // 鎖

    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<Object> getList() {

         return list;

    }

    public void setList(LinkedList<Object> list) {

         this.list = list;

    }

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章