《Java併發編程的藝術》之同步工具

CountDownLatch

該類主要實現了:讓一個線程等待其餘線程完成後再執行的功能,比如Thread.join()java

該類的初始化須要一個整數值count,當每次調用CountDownLatch.countDown()時Count會遞減。直到count降到0時,全部執行CountDownLatch.await()的方法都會返回。算法

初始化了一個共享變量latch,並賦予count爲3數據庫

CountDownLatch latch = new CountDownLatch(3);

建立一個任務,睡眠1秒僞裝執行任務,最後執行countDownide

@Override
public void run() throw InterruptedException{
    System.out.println("執行任務...");
    Thread.sleep(1000);
    latch.countDown();
}

主線程裏執行以下方法工具

// 調用3個線程執行上述的任務
...
latch.await();
System.out.println("執行結束")

當三個任務線程所有執行完latch.countDown()時,main線程就會從阻塞的await()中返回,最後輸出"執行結束"。
注意:CountDownLatch 只能使用一次,下一次使用要從新建立一個。學習

CylicBarrier

該類和CountDownLatch有點相似,不過從名字就能夠看出它是一個可循環使用 的類。它的功能主要是等待全部線程達到某個位置,而後統一執行。能夠想象成出發旅遊,你們都先到集合地等待,待全部人都到了,就能夠出發了。線程

建立一個屏障code

CyclicBarrier barrier = new CyclicBarrier(4);

任務類,讓先完成的任務進行等待,等待其餘線程到達get

@Override
public void run() throw InterruptedException{
    System.out.println(Thread.currentThread.getName() + " -> 到達集合點");
    barrier.await();
    System.out.println(Thread.currentThread.getName() + "出發!")
}

睡5秒,不讓主線程過早結束同步

// 建立4個線程執行上述的任務
...
Thread.sleep(5000);
System.out.println("執行結束")

注意,若是barrier在等待過程當中某個線程被中斷了一次,那麼整個barrier就須要從新來過。

Thread thread = new Thread(() -> {
    try {
        barrier.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (BrokenBarrierException e) {
        e.printStackTrace();
    }
});
thread.start();
thread.interrupt();
try{
    barrier.await();
}catch (Exception e){
    System.out.println("沒法等待...");
}

當另起的線程被中斷後,後續的barrier就沒法使用了,會拋出BrokenBarrierException

Semaphore

該類被稱做信號量,用於控制同一時間的線程執行數。想象下面一副場景:

-----------------
🚌     🚌 🚌 🚌↘---------------
🚌   🚌   🚌    🚌🚌  🚌🚌
   🚌    🚌  🚌↗---------------
-----------------

在窄路口裏每次只能經過5輛車,5輛車經過後,後5輛車才能經過。Semaphore的做用就和它很相似,當有20條線程在執行IO密集型的任務,執行完後須要將處理結果存儲到數據庫中。若是數據庫鏈接只有10條,那就要用semaphore去控制拿到數據庫鏈接的線程數量。

Semaphore裏沒用過的方法:

  • hasQueuedThreads():是否有等待的線程
  • getQueueLength():返回正在等待獲取許可證的線程數量

Exchanger

該類是一個用於線程間協做的工具類。Exchanger用於進行線程間的數據交換。它提供一個同步點,在這個通不見,兩個線程能夠交換彼此間的數據。這兩個線程經過exchange方法交換數據:若是第一個線程執行exchange(),它會一直等待第二個線程exchange(),當兩個線程達到同步點,這兩個線程就能夠交換線程。
雖然我不知道這個類有啥做用(ε=ε=ε=┏(゜ロ゜;)┛
可是書上說能夠用於遺傳算法、校對工做:

Exchanger<String> exchanger = new Exchanger<>();

new Thread(() -> {
    String dataOfAThread = Thread.currentThread().getName() + "-----A的數據";
    try {
        String resultOfBThread = exchanger.exchange(dataOfAThread);
        System.out.println(Thread.currentThread().getName() + "-------> " + resultOfBThread);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

new Thread(() -> {
    String dataOfBThread = Thread.currentThread().getName() + "-----B的數據";
    try {
        String resultOfAThread = exchanger.exchange(dataOfBThread);
        System.out.println(Thread.currentThread().getName() + "-------> " + resultOfAThread);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();

最後輸出:

Thread-1-------> Thread-0-----A的數據
Thread-0-------> Thread-1-----B的數據

總結

從新熟悉一下同步工具,學習到了CyclicBarrier被中斷一次後,整個做廢的點;學習到了Exchanger的適用場景

相關文章
相關標籤/搜索