併發-6-wait、notify、Semaphore、CountDownLatch、CyclicBarrier

Coding挖掘機發表於2018-10-17

wait()、notify()和notifyAll()是Object類中的方法:

  為什麼wait()等方法是在Object中而不是Thread中呢?

  同理,wait(),notify()是對等待這個Object(鎖)的執行緒進行阻塞,喚醒等操作的,當然也要放在Object中

  假設,wait(),notify()放在Thead中,那麼Thread可能等待很多個鎖,操作起來也很複雜

  如果呼叫某個物件的wait()方法,當前執行緒必須擁有這個物件的monitor(即鎖),因此呼叫wait()方法必須在同步塊或者同步方法中進行(synchronized塊或者synchronized方法)

  呼叫某個物件的wait()方法,相當於讓當前執行緒交出此物件的monitor,然後進入等待狀態,等待後續再次獲得此物件的鎖(Thread類中的sleep方法使當前執行緒暫停執行一段時間,從而讓其他執行緒有機會繼續執行,但它並不釋放物件鎖)

  同樣地,呼叫某個物件的notify()方法,當前執行緒也必須擁有這個物件的monitor,因此呼叫notify()方法必須在同步塊或者同步方法中進行(synchronized塊或者synchronized方法)

進階一訊號量

  Java 提供了經典訊號量(Semaphore)的實現,通過控制一定數量的允許(permit)的方式,來達到限制通用資源訪問的目的。   你可以想象一下這個場景,在車站、機場等計程車時,當很多空計程車就位時,為防止過度擁擠,排程員指揮排隊,等待坐車的隊伍一次進來5個人上車, 等這5個人坐車出發,再放進去下一批 當訊號量的大小為1時,與synchronized沒有區別

public class SemaphoreTest {
    private static Semaphore semaphore = new Semaphore(5);

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new CarWorker(semaphore).start();
        }
    }
}

class CarWorker extends Thread {
    private Semaphore semaphore;

    public CarWorker(Semaphore semaphore) {
        this.semaphore = semaphore;
    }

    @Override
    public void run() {
        try {
            out.println(Thread.currentThread() + " waiting permitted");
            semaphore.acquire();
            out.println(Thread.currentThread() + " on car !");
            Thread.sleep(10000);
        } catch (Exception e) {
        } finally {
            out.println(Thread.currentThread() + " release permitted");
            semaphore.release();
        }
    }
}
複製程式碼

進階-CountDownLatch

  一次性使用的計數器,當CountDownLatch中數值為0時,所有await的執行緒得到喚醒   特別適合於A執行緒需要等待B和C執行緒的結果作為引數的這種場景   

public class CountDownLatchTest {
    public static void main(String[] args) {
        CountDownLatch countDownLatch = new CountDownLatch(6);
        for (int i = 0; i < 5; i++) {
            new FirstBatchPassenger(countDownLatch).start();
        }

        for (int i = 0; i < 5; i++) {
            new SecondBatchPassenger(countDownLatch).start();
        }

        while (countDownLatch.getCount() != 1) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
        out.println("MainThread countDown!");
        countDownLatch.countDown();
    }
}

class FirstBatchPassenger extends Thread {
    private CountDownLatch countDownLatch;

    public FirstBatchPassenger(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        out.println("FirstBatchPassenger Executed!");
        countDownLatch.countDown();
    }
}

class SecondBatchPassenger extends Thread {
    private CountDownLatch countDownLatch;

    public SecondBatchPassenger(CountDownLatch countDownLatch) {
        this.countDownLatch = countDownLatch;
    }

    @Override
    public void run() {
        try {
            countDownLatch.await();
            out.println("SecondBatchPassenger Executed!");
        } catch (InterruptedException e) {
        }
    }
}
複製程式碼

輸出:

FirstBatchPassenger Executed!
FirstBatchPassenger Executed!
FirstBatchPassenger Executed!
FirstBatchPassenger Executed!
FirstBatchPassenger Executed!
MainThread countDown!
SecondBatchPassenger Executed!
SecondBatchPassenger Executed!
SecondBatchPassenger Executed!
SecondBatchPassenger Executed!
SecondBatchPassenger Executed!
複製程式碼

進階三-CyclicBarrier

觸發屏障,當await自動達到屏障數量時,觸發屏障操作。可重複使用!

public class CyclicBarrierTest {

    public static void main(String[] args) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> out.println("Action GO!"));
        for (int i = 0; i<6;i++){
            new CyclicBarrierWorker(cyclicBarrier).start();
        }
    }
}

class CyclicBarrierWorker extends Thread {
    private CyclicBarrier cyclicBarrier;
    public CyclicBarrierWorker(CyclicBarrier cyclicBarrier) {
        this.cyclicBarrier = cyclicBarrier;
    }

    @Override
    public void run() {
        out.println("Executed!");
        try {
            cyclicBarrier.await();
        } catch (InterruptedException e) {
        } catch (BrokenBarrierException e) {
        }
    }
}
複製程式碼

輸出:

Executed!
Executed!
Executed!
Action GO!
Executed!
Action GO!
Executed!
Executed!
Action GO!
複製程式碼

相關文章