摘要:演示代碼獲取一個(gè)許可釋放一個(gè)許可我們?cè)趫?zhí)行方式前后包裹上和,這樣其實(shí)我們就相當(dāng)于一個(gè)單線程在執(zhí)行。嘗試獲取一個(gè)許可釋放一個(gè)許可這次我們使用的是一個(gè)方法,這個(gè)方法的第一個(gè)參數(shù)是表示等待毫秒,第二參數(shù)是表示多長(zhǎng)時(shí)間嘗試一次,表示毫秒。
Semaphore
是用于控制某個(gè)資源同一時(shí)間被線程訪問的個(gè)數(shù),提供acquire()和release()方法,acquire獲取一個(gè)許可,如果沒有獲取的到就等待,release是在操作完成后釋放一個(gè)許可,Semaphore維護(hù)了當(dāng)前訪問的個(gè)數(shù),通過同步機(jī)制來(lái)控制同時(shí)訪問的個(gè)數(shù),在數(shù)據(jù)結(jié)構(gòu)里鏈表中的節(jié)點(diǎn)是可以無(wú)限個(gè)的,而Semaphore里維護(hù)的是一個(gè)有大小的限鏈表。
Semaphore用于僅能提供有限訪問的資源,比如數(shù)據(jù)庫(kù)中的鏈接數(shù)只有20但是我們上層應(yīng)用數(shù)可能遠(yuǎn)大于20,如果同時(shí)都對(duì)數(shù)據(jù)庫(kù)鏈接進(jìn)行獲取,那很定會(huì)因?yàn)殒溄荧@取不到而報(bào)錯(cuò),所以我們就要對(duì)數(shù)據(jù)庫(kù)鏈接的訪問進(jìn)行控制。
@Slf4j public class SemaphoreExample1 { private final static int threadCount = 20; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(3); for (int i = 0; i < threadCount; i++) { final int threadNum = i; exec.execute(() -> { try { semaphore.acquire(); // 獲取一個(gè)許可 test(threadNum); semaphore.release(); // 釋放一個(gè)許可 } catch (Exception e) { log.error("exception", e); } }); } exec.shutdown(); } private static void test(int threadNum) throws Exception { log.info("{}", threadNum); Thread.sleep(1000); } }
我們?cè)趫?zhí)行 test(threadNum)方式前后包裹上acquire和release,這樣其實(shí)我們就相當(dāng)于一個(gè)單線程在執(zhí)行。當(dāng)執(zhí)行acquire后就只能等待執(zhí)行release后再執(zhí)行新的線程,然后我們?cè)赼cquire()和release()都是沒有傳參也就是1,每次只允許一個(gè)線程執(zhí)行,如果我們改成
semaphore.acquire(3); // 獲取多個(gè)許可 test(threadNum); semaphore.release(3); // 釋放多個(gè)許可
那么我們就是每3個(gè)3個(gè)執(zhí)行直到把線程池中的線程執(zhí)行完。在打印的日志中我們也可以看到是每三個(gè)每三個(gè)打印。
Semaphore提供了一個(gè)嘗試獲取許可的方法,tryAcquire()嘗試獲取許可成功就執(zhí)行,嘗試獲取許可失敗就丟棄線程。下面看代碼
@Slf4j public class SemaphoreExample3 { private final static int threadCount = 20; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(3); for (int i = 0; i < threadCount; i++) { final int threadNum = i; exec.execute(() -> { try { if (semaphore.tryAcquire()) { // 嘗試獲取一個(gè)許可 test(threadNum); semaphore.release(); // 釋放一個(gè)許可 } } catch (Exception e) { log.error("exception", e); } }); } exec.shutdown(); } private static void test(int threadNum) throws Exception { log.info("{}", threadNum); Thread.sleep(1000); } }
這段代碼執(zhí)行結(jié)果就只打印了3行日志,其他的線程就被丟棄了。tryAcquire()共提供如下幾種方法。
我們用一個(gè)例子來(lái)演示一下參數(shù)的方法的使用。
@Slf4j public class SemaphoreExample4 { private final static int threadCount = 20; public static void main(String[] args) throws Exception { ExecutorService exec = Executors.newCachedThreadPool(); final Semaphore semaphore = new Semaphore(3); for (int i = 0; i < threadCount; i++) { final int threadNum = i; exec.execute(() -> { try { if (semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS)) { // 嘗試獲取一個(gè)許可 test(threadNum); semaphore.release(); // 釋放一個(gè)許可 } } catch (Exception e) { log.error("exception", e); } }); } exec.shutdown(); } private static void test(int threadNum) throws Exception { log.info("{}", threadNum); Thread.sleep(1000); } }
這次我們使用的是一個(gè)tryAcquire(5000, TimeUnit.MILLISECONDS))方法,這個(gè)方法的第一個(gè)參數(shù)是表示等待5000毫秒,第二參數(shù)是表示多長(zhǎng)時(shí)間嘗試一次,TimeUnit.MILLISECONDS表示1毫秒。這時(shí)候我們會(huì)發(fā)現(xiàn)20個(gè)線程都執(zhí)行了,為什么會(huì)這樣呢?因?yàn)槲覀冊(cè)趫?zhí)行時(shí)等待超時(shí)時(shí)間是5秒,每次執(zhí)行就是sleep 1秒,所以可以獲取成tryAcquire進(jìn)而執(zhí)行。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/77671.html
摘要:性能較好是因?yàn)楸苊饬司€程進(jìn)入內(nèi)核的阻塞狀態(tài)請(qǐng)求總數(shù)同時(shí)并發(fā)執(zhí)行的線程數(shù)我們首先使用聲明一個(gè)所得實(shí)例,然后使用進(jìn)行加鎖和解鎖操作。 ReentrantLock與鎖 Synchronized和ReentrantLock異同 可重入性:兩者都具有可重入性 鎖的實(shí)現(xiàn):Synchronized是依賴jvm實(shí)現(xiàn)的,ReentrantLock是jdk實(shí)現(xiàn)的。(我們可以理解為一個(gè)是操作系統(tǒng)層面的實(shí)現(xiàn)...
摘要:當(dāng)線程使用完共享資源后,可以歸還許可,以供其它需要的線程使用。所以,并不會(huì)阻塞調(diào)用線程。立即減少指定數(shù)目的可用許可數(shù)。方法用于將可用許可數(shù)清零,并返回清零前的許可數(shù)六的類接口聲明類聲明構(gòu)造器接口聲明 showImg(https://segmentfault.com/img/bVbfdnC?w=1920&h=1200); 本文首發(fā)于一世流云的專欄:https://segmentfault...
摘要:簡(jiǎn)介抽象隊(duì)列同步器,以下簡(jiǎn)稱出現(xiàn)在中,由大師所創(chuàng)作。獲取成功則返回,獲取失敗,線程進(jìn)入同步隊(duì)列等待。響應(yīng)中斷版的超時(shí)響應(yīng)中斷版的共享式獲取同步狀態(tài),同一時(shí)刻可能會(huì)有多個(gè)線程獲得同步狀態(tài)。 1.簡(jiǎn)介 AbstractQueuedSynchronizer (抽象隊(duì)列同步器,以下簡(jiǎn)稱 AQS)出現(xiàn)在 JDK 1.5 中,由大師 Doug Lea 所創(chuàng)作。AQS 是很多同步器的基礎(chǔ)框架,比如 ...
摘要:簡(jiǎn)介抽象隊(duì)列同步器,以下簡(jiǎn)稱出現(xiàn)在中,由大師所創(chuàng)作。獲取成功則返回,獲取失敗,線程進(jìn)入同步隊(duì)列等待。響應(yīng)中斷版的超時(shí)響應(yīng)中斷版的共享式獲取同步狀態(tài),同一時(shí)刻可能會(huì)有多個(gè)線程獲得同步狀態(tài)。 1.簡(jiǎn)介 AbstractQueuedSynchronizer (抽象隊(duì)列同步器,以下簡(jiǎn)稱 AQS)出現(xiàn)在 JDK 1.5 中,由大師 Doug Lea 所創(chuàng)作。AQS 是很多同步器的基礎(chǔ)框架,比如 ...
摘要:所有示例代碼請(qǐng)見下載于基本概念并發(fā)同時(shí)擁有兩個(gè)或者多個(gè)線程,如果程序在單核處理器上運(yùn)行多個(gè)線程將交替地?fù)Q入或者換出內(nèi)存這些線程是同時(shí)存在的,每個(gè)線程都處于執(zhí)行過程中的某個(gè)狀態(tài),如果運(yùn)行在多核處理器上此時(shí),程序中的每個(gè)線程都 所有示例代碼,請(qǐng)見/下載于 https://github.com/Wasabi1234... showImg(https://upload-images.jians...
閱讀 3080·2021-09-28 09:43
閱讀 911·2021-09-08 09:35
閱讀 1450·2019-08-30 15:56
閱讀 1196·2019-08-30 13:00
閱讀 2743·2019-08-29 18:35
閱讀 1837·2019-08-29 14:07
閱讀 3443·2019-08-29 13:13
閱讀 1339·2019-08-29 12:40