併發編程 - wait和notifyAll

併發編程之槍械爭奪

需求如下圖:狙擊手們和備彈手們同時爭搶一把槍,槍同時只能被一人持有,且備彈容量上限爲20。狙擊手則使用槍械開槍子彈 -1,備彈手則給槍械上子彈 +1.

問題分析:

    基於面向對象的編程思想,我們首先需要對三者進行抽象,需要創建以下三種類型。

  1. 創建槍械的類,槍械有shot和put方法,有槍械名稱和子彈容量等屬性。
  2. 創建狙擊手類,由於我們是多線程編程,則實現runnable接口,在run方法中使用無限循環調用shot。
  3. 創建備彈手類,實現runnable接口,在run方法中使用無限循環調用put方法。

   在《Effective Java》中,對wait()、notify()、notifyAll()有所描述,作者認爲wait()和notifyAll()是組合使用的,結合實際情況來看,確實是這樣。如果使用notify()只喚醒一個線程,但是該線程卻沒有達到獲取鎖的條件,調用了wait()此時則會發生死鎖的情況。

    wait()使用範式:

        while(不滿足條件){

              wait();

        }

    notifyAll()使用範式:

       同步代碼塊,執行結束的最後一行語句,釋放鎖之前喚醒其他爭搶這把鎖的線程。

    

    synchronized同步鎖使用方式

  1. 同步代碼塊
  2. 同步方法

    synchronized鎖的是什麼呢?

    synchronized使用時需要注意以下幾點:

  1. synchronized鎖要設計好鎖的粒度,減少資源的損耗。
  2. synchronized鎖聲明的方法上,在方法取的方法錢有ANS_SYCHRONIZED標識。
  3. synchronized代碼塊,則反編譯會有monitor enter 和monitor exit方法作爲鎖開始和結束。jvm實現。
  4. synchronized是可重入鎖。
  5. synchronized鎖代碼區間若拋出異常則釋放鎖。
  6. synchronized鎖靜態方法其實鎖的是靜態方法所屬的類對象。
  7. synchronized鎖普通方法鎖的是這個類當前的實例對象。
  8. 一個類中多個方法、synchronized鎖不同的對象,不爭奪同一把鎖的方法可以並行執行。

代碼編寫


public class Weapon {


    public static void main(String[] args) {
        GoldAKGun akGun = new GoldAKGun("黃金AK",10);
        new Thread(new Sniper(akGun),"狙擊手->順溜").start();
        new Thread(new Sniper(akGun),"狙擊手->二嘎").start();
        //new Thread(new Deputy(akGun),"備彈手->二雷").start();
        new Thread(new Deputy(akGun),"備彈手->二毛").start();
        new Thread(new Deputy(akGun),"備彈手->鐵蛋").start();
        new Thread(new Deputy(akGun),"備彈手->大柱").start();
    }


    public static class GoldAKGun{
        private String gunName = "AK";    //默認名字AK
        private Integer bollet = 0;     //默認備彈 0 發

        public GoldAKGun(String gunName, Integer bollet) {
            this.gunName = gunName;
            this.bollet = bollet;
        }

        public synchronized void putBollet(String name){
            try {
                while (bollet>=20){
                    System.out.println(name + "->發現["+ gunName +"]的子彈是滿的 !");
                    this.wait();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            bollet++;
            System.out.println(name + "->成功拿起["+ gunName +"]裝入一枚子彈,當前子彈數目:" + bollet);
            this.notifyAll();
        }

        public synchronized void shotGirld(String name){
            try {
                while (bollet<=0){
                    System.out.println(name + "->發現["+ gunName +"]的彈夾是空的 !");
                    this.wait();
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }

            bollet--;
            System.out.println(name + "->扣動["+ gunName +"]板機,打了個鳥兒,當前子彈數目:" + bollet);
            this.notifyAll();
        }

    }


    public static class Sniper implements Runnable{

        GoldAKGun ak47;

        public Sniper(GoldAKGun ak47){
            this.ak47 = ak47;
        }

        @Override
        public void run(){
            for (;;) {
                sleep(500);
                ak47.shotGirld(Thread.currentThread().getName());
            }
        }
    }

    public static class Deputy implements Runnable{

        GoldAKGun ak47;

        public Deputy(GoldAKGun ak47){
            this.ak47 = ak47;
        }

        @Override
        public void run(){
            for (;;) {
                sleep(1000);
                ak47.putBollet(Thread.currentThread().getName());
            }
        }
    }

    public static void sleep(Integer millis){
        try {
            Thread.sleep(millis);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

總結描述

    synchronized、wait、notifyAll在常用的java開發框架中,多次出現,需要深入的研究一下。

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