Java 信號(hào)量Semaphore的實(shí)現(xiàn)
近日于LeetCode看題遇1114 按序打印,獲悉一解法使用了Semaphore,順勢(shì)研究,記心得于此。
此解視Semaphore為鎖,以保證同一時(shí)刻單線程的順序執(zhí)行。在此原題上,我作出如下更改。
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class SemaphoreDemo { static Semaphore A; static Semaphore B; static Semaphore C; public static void main(String[] args) throws InterruptedException { A = new Semaphore(1); B = new Semaphore(0); C = new Semaphore(0); ExecutorService ex=Executors.newFixedThreadPool(10); for (int i = 0; i <7; i++) { ex.execute(new R1()); ex.execute(new R2()); ex.execute(new R3()); } ex.shutdown(); } public static class R1 implements Runnable{ @Override public void run() { try { // A.acquire(); System.out.println("1"+Thread.currentThread().getName()); // B.release(); } catch (Exception e) { e.printStackTrace(); } } } public static class R2 implements Runnable{ @Override public void run() { try { // B.acquire(); System.out.println("2"+Thread.currentThread().getName()); // C.release(); } catch (Exception e) { e.printStackTrace(); } } } public static class R3 implements Runnable{ @Override public void run() { try { // C.acquire(); System.out.println("3"+Thread.currentThread().getName()); // A.release(); } catch (Exception e) { e.printStackTrace(); } } } }
10個(gè)線程的常量池中,分別調(diào)用R1,R2,R3的方法多次,控制臺(tái)輸出對(duì)應(yīng)各方法名拼接執(zhí)行該方法的線程名。多次執(zhí)行結(jié)果各不相同:
1pool-1-thread-1 2pool-1-thread-2 1pool-1-thread-4 3pool-1-thread-6 2pool-1-thread-5 3pool-1-thread-3 1pool-1-thread-7 2pool-1-thread-8 3pool-1-thread-9 3pool-1-thread-1 2pool-1-thread-8 1pool-1-thread-4 3pool-1-thread-1 1pool-1-thread-2 2pool-1-thread-9 1pool-1-thread-10 3pool-1-thread-1 2pool-1-thread-5 1pool-1-thread-6 3pool-1-thread-4 2pool-1-thread-8
1pool-1-thread-1 2pool-1-thread-2 3pool-1-thread-3 1pool-1-thread-4 2pool-1-thread-5 3pool-1-thread-6 1pool-1-thread-7 2pool-1-thread-8 3pool-1-thread-9 1pool-1-thread-10 3pool-1-thread-1 1pool-1-thread-4 2pool-1-thread-8 3pool-1-thread-3 2pool-1-thread-10 1pool-1-thread-2 2pool-1-thread-9 3pool-1-thread-4 1pool-1-thread-7 3pool-1-thread-6 2pool-1-thread-5
方法能調(diào)用,多線程下卻無法保證方法的順序執(zhí)行。使用Semaphore后,代碼為:
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; public class SemaphoreDemo { static Semaphore A; static Semaphore B; static Semaphore C; public static void main(String[] args) throws InterruptedException { A = new Semaphore(1); B = new Semaphore(0); C = new Semaphore(0); ExecutorService ex=Executors.newFixedThreadPool(10); for (int i = 0; i <7; i++) { ex.execute(new R1()); ex.execute(new R2()); ex.execute(new R3()); } ex.shutdown(); } public static class R1 implements Runnable{ @Override public void run() { try { A.acquire(); System.out.println("1"+Thread.currentThread().getName()); B.release(); } catch (Exception e) { e.printStackTrace(); } } } public static class R2 implements Runnable{ @Override public void run() { try { B.acquire(); System.out.println("2"+Thread.currentThread().getName()); C.release(); } catch (Exception e) { e.printStackTrace(); } } } public static class R3 implements Runnable{ @Override public void run() { try { C.acquire(); System.out.println("3"+Thread.currentThread().getName()); A.release(); } catch (Exception e) { e.printStackTrace(); } } } }
多次運(yùn)行結(jié)果皆能保證1、2、3的順序:
1pool-1-thread-1 2pool-1-thread-2 3pool-1-thread-3 1pool-1-thread-4 2pool-1-thread-5 3pool-1-thread-6 1pool-1-thread-7 2pool-1-thread-8 3pool-1-thread-9 1pool-1-thread-10 2pool-1-thread-1 3pool-1-thread-2 1pool-1-thread-3 2pool-1-thread-4 3pool-1-thread-5 1pool-1-thread-6 2pool-1-thread-9 3pool-1-thread-7 1pool-1-thread-10 2pool-1-thread-8 3pool-1-thread-1
附上api文檔鏈接 Semaphore
A = new Semaphore(1);
B = new Semaphore(0);
C = new Semaphore(0);
進(jìn)入R2、R3方法的線程會(huì)執(zhí)行acquire()方法,而B、C中的計(jì)數(shù)器為0獲取不到許可,阻塞直到一個(gè)可用,或者線程被中斷,不能繼續(xù)執(zhí)行。R1方法中A尚有1個(gè)許可可拿到,方法執(zhí)行,并給B發(fā)布一個(gè)許可,若B先于A執(zhí)行acquire(),此時(shí)B為阻塞狀態(tài),則獲取到剛剛發(fā)布的許可,該線程被重新啟用。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
RestTemplate報(bào)錯(cuò)I/O?error?on?POST?request?for的解決辦法
這篇文章主要給大家介紹了關(guān)于RestTemplate報(bào)錯(cuò)I/O?error?on?POST?request?for的解決辦法,文中通過代碼實(shí)例將解決的辦法介紹的非常詳細(xì),需要的朋友可以參考下2023-08-08深入Java7的一些新特性以及對(duì)腳本語言支持API的介紹
本篇文章是對(duì)Java7的一些新特性以及對(duì)腳本語言支持API的概述,需要的朋友參考下2013-05-05如何在Spring Boot應(yīng)用程序中配置了兩個(gè)不同的SOAP Web服務(wù)端點(diǎn)
這篇文章主要介紹了如何在Spring Boot應(yīng)用程序中配置了兩個(gè)不同的SOAP Web服務(wù)端點(diǎn),本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-08-08SpringBoot發(fā)送html郵箱驗(yàn)證碼功能
這篇文章主要介紹了SpringBoot發(fā)送html郵箱驗(yàn)證碼,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12java中 Set與Map排序輸出到Writer詳解及實(shí)例
這篇文章主要介紹了 java中 Set與Map排序輸出到Writer詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-03-03如何將復(fù)雜SQL轉(zhuǎn)換成Java對(duì)象的實(shí)例講解
轉(zhuǎn)換復(fù)雜SQL到Java代碼,我們需要確定數(shù)據(jù)庫連接方式和工具,使用JDBC的API來連接數(shù)據(jù)庫、執(zhí)行SQL語句,復(fù)雜SQL語句可以被拆分為多個(gè)步驟,每個(gè)步驟執(zhí)行一個(gè)特定的操作,通過將SQL語句拆分為多個(gè)步驟,我們可以更好地理解復(fù)雜SQL的邏輯,并且更容易將其轉(zhuǎn)換為Java代碼2024-05-05java定位死鎖的三種方法(jstack、Arthas和Jvisualvm)
這篇文章主要給大家介紹了關(guān)于java定位死鎖的三種方法,分別是通過jstack定位死鎖信息、通過Arthas工具定位死鎖以及通過 Jvisualvm 定位死鎖,文中還介紹了死鎖的預(yù)防方法,需要的朋友可以參考下2021-09-09Java 實(shí)現(xiàn)加密數(shù)據(jù)庫連接的步驟
這篇文章主要介紹了Java 實(shí)現(xiàn)加密數(shù)據(jù)庫連接的步驟,幫助大家更好的理解和使用Java處理數(shù)據(jù)庫,感興趣的朋友可以了解下2020-11-11