Java併發編程藝術 8 Java中的併發工具類

第8章 Java中的併發工具類

併發工具類中主要提供了一些併發流程控制的手段。主要有CountDownLatch、CyclicBarriery和Semaphore
Exchanger工具類提供在線程間交換數據的一種手段。


CountDownLatch 
CountDownLatch類能夠使一個線程進行等待,等待其他相關的線程完成各自的任務以後再執行當前線程的工作。
例如:一個程序的主線程希望負責啓動框架的所有主線程完成以後再繼續執行。

CountDownLatch是通過一個計數器來實現的,計數器的初始值就是相關線程的數量。當每一個相關線程完成任務的時候,對計數器的值減1。當計數器的值到達0時,他表示所有的相關線程已經完成了任務。然後使用CountDownLatch閉鎖上等待的線程可以繼續執行任務。(建議將countDown()放在finally裏運行)
1.主線程線程開始
2.在主線程中創建一個CountDownLatch,根據N個相關線程。CountDownLatch初始值爲N。
3.主線程使用await,在CountDownLatch上等待
4.相關線程完成任務後,對CountDownLatch減1.  countDown()。
5.當CountDownLatch爲0時,主線程繼續運行。
CountDownLatch的三個基本元素
CountDownLatch latch = new CountDownLatch(5); //主線程
latch.await()
latch.countDown() //子線程

CountDownLatch對象內部計數器的值只能被初始化一次,必能重新初始化。一旦賦值以後,以爲能修改計數的方法就是countDown()方法,對內部計數器減1。 當計數器到達0時, 全部調用 await() 方法會立刻返回,接下來任何countDown() 方法的調用都將不會造成任何影響。
總結:
CountDownLatch是同步工具類中的一種。可以使一個線程進行等待,直到其他線程執行完畢後再執行當前線程。是通過內部計數器來實現的,每完成一個任務就對計數器進行減1。直到爲0,閉鎖等待的線程就可以恢復執行。可以用來實現線程等待和最大並行性。

CyclicBarriery
CyclicBarriery的默認構造方法CyclicBarrier(int parties),初始化參數表示屏障攔截的線程數。
當每一個線程調用await的時候通知CyclicBarrier已經到達屏障,然後當前線程被阻塞在await()方法上。
等到攔截到初始化時設定的線程數時,所有線程繼續執行,之後再執行await()不會再等待。如果沒有攔截到指定數量的線程,這全部都阻塞。

CyclicBarriery還提供了更高級的構造,可以傳入barrierAction(Runnable類型),當所有線程到達屏障時,優先執行barrierAction。可以用作所有屏障到達的一個通知點
static CyclicBarrier b = new CyclicBarrier(10);

static CyclicBarrier b = new CyclicBarrier(10,new Runnable() {
     public void run() {
           System.out.println("hahhha");
     }
});

public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
     for(int i=0;i<10;i++){
           new Thread(new MRunnable()).start();
     }
     b.await();
     System.out.println("main");
     b.reset();
     b.await();
     System.out.println("main");
     
}
static class MRunnable implements Runnable{
     public void run() {
           try {
                Thread.sleep(5000);
                System.out.println("MRunnanle1 ");
                b.await();
           } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
           }
     }
}

實現最大的並行性:有時我們想同時啓動多個線程,實現最大程度的並行性。
開始執行前等待n個線程完成各自任務:例如應用程序啓動類要確保在處理用戶請求前,所有N個外部系統已經啓動和運行了。
通過將await()放在任務前還是任務後,來實現以上兩種功能。

CountDownLatch 和CyclicBarrier區別
【1】.CountDownLatch計數器只能使用一次,CyclicBarrier的計數器可以通過reset()重置。
【2】CyclicBarrier中還提供了getNumberWaiting()方法獲取阻塞的線程數。,以及一些其他方法。
【3】CountDownLatch使用減計數方式,從指定值開始減,減到爲0釋放所有線程。CyclicBarrier使用加計數方式,從0開始加到指定值釋放所有線程
【4】CountDownLatch 的await()只負責阻塞,使用CountDown()方法減一。CyclicBarrier的await(),負責阻塞,並且對計數加一。

Semaphore
Semaphore(信號量)用於控制同時訪問特定資源的線程數量,可以協調各個線程保證合理的使用公共資源。
比如:訪問共享文件,只允許最多十個線程同時訪問。比如數據庫連接,最多支持十個線程連接。
static Semaphore s = new Semaphore(10);

public static void main(String[] args) throws InterruptedException {
     for(int i=0;i<30;i++){
           new Thread(new MyRunnabe()).start();
     }
     Thread.sleep(2000);
     System.out.println(s.availablePermits());
     System.out.println(s.getQueueLength());
     while(true){
           if (s.getQueueLength()==0) {
                break;
           }
           System.out.println("in waiting thread : "+s.getQueueLength());
           Thread.sleep(5000);
     }
}
static class MyRunnabe implements Runnable{
     public void run() {
           try {
                s.acquire();
                System.out.println("out");
                Thread.sleep(10000);
                s.release();
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
     }

}

int availablePermits()  放回信號量中可用的許可證數量
int getQueueLength()    返回正在等待獲取許可證的線程數
boolean  hasQueuedThread() 當前是否有線程正在等待許可證
void  reducePermits()  減少許可證數量,是protected方法
Collection getQueuedThreads()  返回所有等待的獲取許可證的線程集合,是protected方法。


Exchanger
線程間交換數據。Exchanger(交換者)是線程間協作的工具類。用於線程之間的數據交換。
提供一個同步點,實現兩個線程之間的數據交換。當一個線程執行了exchange方法,會等待另個線程執行exchange方法。當兩個線程同時到達同步點就可以交換數據,將本線程的數據傳遞給對方。










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