国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Semaphore,CountDownLatch,CyclicBarrier

2019-11-08 02:58:51
字體:
來源:轉載
供稿:網友

1、atomic包的原理及分析

概論:

CountDownLatch是一個計數器閉鎖,主要的功能就是通過await()方法來阻塞住當前線程,然后等待計數器減少到0了,再喚起這些線程繼續執行。 這個類里主要有兩個方法,一個是向下減計數器的方法countdown();Semaphore與CountDownLatch相似,不同的地方在于Semaphore的值被獲取到后是可以釋放的,并不像CountDownLatch那樣一直減到底。它也被更多地用來限制流量,類似閥門的 功能。如果限定某些資源最多有N個線程可以訪問,那么超過N個主不允許再有線程來訪問,同時當現有線程結束后,就會釋放,然后允許新的線程進來。有點類似于鎖的lock與 unlock過程。相對來說他也有兩個主要的方法: 用于獲取權限的acquire(),其底層實現與CountDownLatch.countdown()類似;用于釋放權限的release(),其底層實現與acquire()是一個互逆的過程。

CyclicBarrier是用來一個關卡來阻擋住所有線程,等所有線程全部執行到關卡處時,再統一執行下一步操作,它里面最重要的方法是await()方法

Semaphore一個計數信號量。從概念上講,信號量維護了一個許可集。如有必要,在許可可用前會阻塞每一個 acquire(),然后再獲取該許可。每個 release() 添加一個許可,從而可能釋放一個正在阻塞的獲取者。但是,不使用實際的許可對象,Semaphore 只對可用許可的號碼進行計數,并采取相應的行動;

Semaphore 通常用于限制可以訪問某些資源(物理或邏輯的)的線程數目。例如,下面的類使用信號量控制對內容池的訪問:

class Pool { PRivate static final int MAX_AVAILABLE = 100; private final Semaphore available = new Semaphore(MAX_AVAILABLE, true); public Object getItem() throws InterruptedException { available.acquire(); return getNextAvailableItem(); } public void putItem(Object x) { if (markAsUnused(x)) available.release(); } // Not a particularly efficient data structure; just for demo protected Object[] items = ... whatever kinds of items being managed protected boolean[] used = new boolean[MAX_AVAILABLE]; protected synchronized Object getNextAvailableItem() { for (int i = 0; i < MAX_AVAILABLE; ++i) { if (!used[i]) { used[i] = true; return items[i]; } } return null; // not reached } protected synchronized boolean markAsUnused(Object item) { for (int i = 0; i < MAX_AVAILABLE; ++i) { if (item == items[i]) { if (used[i]) { used[i] = false; return true; } else return false; } } return false; } }獲得一項前,每個線程必須從信號量獲取許可,從而保證可以使用該項。該線程結束后,將項返回到池中并將許可返回到該信號量,從而允許其他線程獲取該項。注意,調用 acquire() 時無法保持同步鎖,因為這會阻止將項返回到池中。信號量封裝所需的同步,以限制對池的訪問,這同維持該池本身一致性所需的同步是分開的。 將信號量初始化為 1,使得它在使用時最多只有一個可用的許可,從而可用作一個相互排斥的鎖。這通常也稱為二進制信號量,因為它只能有兩種狀態:一個可用的許可,或零個可用的許可。按此方式使用時,二進制信號量具有某種屬性(與很多 Lock 實現不同),即可以由線程釋放“鎖”,而不是由所有者(因為信號量沒有所有權的概念)。在某些專門的上下文(如死鎖恢復)中這會很有用。 此類的構造方法可選地接受一個公平 參數。當設置為 false 時,此類不對線程獲取許可的順序做任何保證。特別地,闖入 是允許的,也就是說可以在已經等待的線程前為調用 acquire() 的線程分配一個許可,從邏輯上說,就是新線程將自己置于等待線程隊列的頭部。當公平設置為 true 時,信號量保證對于任何調用獲取方法的線程而言,都按照處理它們調用這些方法的順序(即先進先出;FIFO)來選擇線程、獲得許可。注意,FIFO 排序必然應用到這些方法內的指定內部執行點。所以,可能某個線程先于另一個線程調用了 acquire,但是卻在該線程之后到達排序點,并且從方法返回時也類似。還要注意,非同步的 tryAcquire 方法不使用公平設置,而是使用任意可用的許可。

通常,應該將用于控制資源訪問的信號量初始化為公平的,以確保所有線程都可訪問資源。為其他的種類的同步控制使用信號量時,非公平排序的吞吐量優勢通常要比公平考慮更為重要。

CountDownLatch一個同步輔助類,在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。 用給定的計數 初始化 CountDownLatch。由于調用了 countDown() 方法,所以在當前計數到達零之前,await 方法會一直受阻塞。之后,會釋放所有等待的線程,await 的所有后續調用都將立即返回。這種現象只出現一次——計數無法被重置。如果需要重置計數,請考慮使用 CyclicBarrier。 CountDownLatch 是一個通用同步工具,它有很多用途。將計數 1 初始化的 CountDownLatch 用作一個簡單的開/關鎖存器,或入口:在通過調用 countDown() 的線程打開入口前,所有調用 await 的線程都一直在入口處等待。用 N 初始化的 CountDownLatch 可以使一個線程在 N 個線程完成某項操作之前一直等待,或者使其在某項操作完成 N 次之前一直等待。

CountDownLatch 的一個有用特性是,它不要求調用 countDown 方法的線程等到計數到達零時才繼續,而在所有線程都能通過之前,它只是阻止任何線程繼續通過一個 await。

示例用法: 下面給出了兩個類,其中一組 worker 線程使用了兩個倒計數鎖存器: 第一個類是一個啟動信號,在 driver 為繼續執行 worker 做好準備之前,它會阻止所有的 worker 繼續執行。 第二個類是一個完成信號,它允許 driver 在完成所有 worker 之前一直等待。

class Driver { // ... void main() throws InterruptedException { CountDownLatch startSignal = new CountDownLatch(1); CountDownLatch doneSignal = new CountDownLatch(N); for (int i = 0; i < N; ++i) // create and start threads new Thread(new Worker(startSignal, doneSignal)).start(); doSomethingElse(); // don't let run yet startSignal.countDown(); // let all threads proceed doSomethingElse(); doneSignal.await(); // wait for all to finish } } class Worker implements Runnable { private final CountDownLatch startSignal; private final CountDownLatch doneSignal; Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { this.startSignal = startSignal; this.doneSignal = doneSignal; } public void run() { try { startSignal.await(); doWork(); doneSignal.countDown(); } catch (InterruptedException ex) {} // return; } void doWork() { ... } }CyclicBarrier 一個同步輔助類,它允許一組線程互相等待,直到到達某個公共屏障點 (common barrier point)。在涉及一組固定大小的線程的程序中,這些線程必須不時地互相等待,此時 CyclicBarrier 很有用。因為該 barrier 在釋放等待線程后可以重用,所以稱它為循環 的 barrier。 CyclicBarrier 支持一個可選的 Runnable 命令,在一組線程中的最后一個線程到達之后(但在釋放所有線程之前),該命令只在每個屏障點運行一次。若在繼續所有參與線程之前更新共享狀態,此屏障操作 很有用。

示例用法:下面是一個在并行分解設計中使用 barrier 的例子:

class Solver { final int N; final float[][] data; final CyclicBarrier barrier; class Worker implements Runnable { int myRow; Worker(int row) { myRow = row; } public void run() { while (!done()) { processRow(myRow); try { barrier.await(); } catch (InterruptedException ex) { return; } catch (BrokenBarrierException ex) { return; } } } } public Solver(float[][] matrix) { data = matrix; N = matrix.length; barrier = new CyclicBarrier(N, new Runnable() { public void run() { mergeRows(...); } }); for (int i = 0; i < N; ++i) new Thread(new Worker(i)).start(); waitUntilDone(); } }

在這個例子中,每個 worker 線程處理矩陣的一行,在處理完所有的行之前,該線程將一直在屏障處等待。處理完所有的行之后,將執行所提供的 Runnable 屏障操作,并合并這些行。如果合并者確定已經找到了一個解決方案,那么 done() 將返回 true,所有的 worker 線程都將終止。

如果屏障操作在執行時不依賴于正掛起的線程,則線程組中的任何線程在獲得釋放時都能執行該操作。為方便此操作,每次調用 await() 都將返回能到達屏障處的線程的索引。然后,您可以選擇哪個線程應該執行屏障操作,例如: if (barrier.await() == 0) { // log the completion of this iteration } 對于失敗的同步嘗試,CyclicBarrier 使用了一種要么全部要么全不 (all-or-none) 的破壞模式:如果因為中斷、失敗或者超時等原因,導致線程過早地離開了屏障點,那么在該屏障點等待的其他所有線程也將通過 BrokenBarrierException(如果它們幾乎同時被中斷,則用 InterruptedException)以反常的方式離開。

內存一致性效果:線程中調用 await() 之前的操作 happen-before 那些是屏障操作的一部份的操作,后者依次 happen-before 緊跟在從另一個線程中對應 await() 成功返回的操作。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 西城区| 图片| 乌鲁木齐县| 徐水县| 华宁县| 西畴县| 永定县| 临泉县| 夏河县| 桐柏县| 巴楚县| 星子县| 商城县| 若尔盖县| 萨迦县| 玛沁县| 沁源县| 武乡县| 来宾市| 江都市| 平湖市| 惠来县| 南皮县| 望城县| 陵川县| 手游| 丹阳市| 肃宁县| 临夏市| 健康| 叙永县| 毕节市| 科尔| 白水县| 通山县| 乌兰察布市| 平遥县| 宜丰县| 绵阳市| 浏阳市| 湖州市|