java多線程實(shí)現(xiàn)有序輸出ABC
3個(gè)線程,線程1輸出A,線程2輸出B,線程3輸出C,讓這個(gè)3個(gè)線程循環(huán)有序地輸出ABCABC…
看到這個(gè)題目,感覺很有意思,問題的本質(zhì)是在多線程執(zhí)行環(huán)境,控制線程的執(zhí)行順序,實(shí)現(xiàn)的方式有非常多種,本質(zhì)上需要解決Java多線程環(huán)境下的線程執(zhí)行的同步和利用鎖機(jī)制來控制線程的執(zhí)行順序。
方式1:利用synchronized
這種方式也就是使用java內(nèi)置的monitor機(jī)制,配合wait和notifyAll,代碼如下:
(1)利用volatile做線程間資源的同步訪問,同時(shí)作為線程調(diào)度的標(biāo)志;
(2)利用notifyAll來喚醒其他等待當(dāng)前的monitor資源的線程;
public class ThreadOrderWithSync { private volatile int flag = 'A'; private final static Object LOCK = new Object(); Runnable a = () -> { while (true) { synchronized (LOCK) { if (flag == 'A' ) { System.out.println("A"); flag = 'B'; // let other thread race to get the monitor LOCK.notifyAll(); } else { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }; Runnable b = () -> { while (true) { synchronized (LOCK) { if (flag == 'B' ) { System.out.println("B"); flag = 'C'; // let other thread race to get the monitor LOCK.notifyAll(); } else { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }; Runnable c = () -> { while (true) { synchronized (LOCK) { if (flag == 'C' ) { System.out.println("C"); flag = 'A'; // let other thread race to get the monitor LOCK.notifyAll(); } else { try { LOCK.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }; public void runTest() { Thread ta = new Thread(a); Thread tb = new Thread(b); Thread tc = new Thread(c); ta.start(); tb.start(); tc.start(); } public static void main(String[] args) { ThreadOrderWithSync sync = new ThreadOrderWithSync(); sync.runTest(); } }
方式2:利用并發(fā)包ReentrantLock和Condition的鎖機(jī)制
上面方式1的synchronized機(jī)制,因?yàn)楫?dāng)前的所有線程都爭(zhēng)用同一個(gè)monitor資源,因此只能通過notifyAll來通知其他線程來加鎖,因此每次都會(huì)出現(xiàn)race condition,但是,通過ReentrantLock的Condition,我們可以精確控制,下一個(gè)該喚醒signal的線程是哪一個(gè)(因?yàn)槲覀冎缊?zhí)行的順序是A->B->C的循環(huán)),相比synchronized的機(jī)制,Condition機(jī)制可以更精細(xì)化線程的調(diào)度設(shè)計(jì),代碼示例如下:
/** * @author xijin.zeng created on 2018/8/31 * Thrads runing order: A->B->C */ public class ThreadOrderWithCondition { private static final ReentrantLock LOCK = new ReentrantLock(); private static final Condition C_A = LOCK.newCondition(); private static final Condition C_B = LOCK.newCondition(); private static final Condition C_C = LOCK.newCondition(); /** * init for A to run first */ private volatile int flag = 'A'; Runnable a = () -> { while (true) { LOCK.lock(); if (flag == 'A') { System.out.println("A"); flag = 'B'; // signal B to run C_B.signal(); } else { try { // block and wait signal to invoke C_A.await(); } catch (InterruptedException e) { e.printStackTrace(); } } LOCK.unlock(); } }; Runnable b = () -> { while (true) { LOCK.lock(); if (flag == 'B') { System.out.println("B"); flag = 'C'; // signal C to run C_C.signal(); } else { try { // block and wait signal to invoke C_B.await(); } catch (InterruptedException e) { e.printStackTrace(); } } LOCK.unlock(); } }; Runnable c = () -> { while (true) { LOCK.lock(); if (flag == 'C') { System.out.println("C"); flag = 'A'; // signal A to run C_A.signal(); } else { try { // block and wait signal to invoke C_C.await(); } catch (InterruptedException e) { e.printStackTrace(); } } LOCK.unlock(); } }; public void runTest() { Thread threadA = new Thread(a); Thread threadB = new Thread(b); Thread threadC = new Thread(c); threadA.start(); threadB.start(); threadC.start(); } public static void main(String[] args) { ThreadOrderWithCondition o = new ThreadOrderWithCondition(); o.runTest(); } }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
圖數(shù)據(jù)庫(kù)NebulaGraph的Java 數(shù)據(jù)解析實(shí)踐與指導(dǎo)詳解
這篇文章主要介紹了圖數(shù)據(jù)庫(kù)NebulaGraph的Java 數(shù)據(jù)解析實(shí)踐與指導(dǎo)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04IDEA新建JAVA項(xiàng)目簡(jiǎn)單圖文教程
這篇文章主要給大家介紹了關(guān)于IDEA新建JAVA項(xiàng)目的相關(guān)資料,IDEA是現(xiàn)在java中最為常用的編譯器,所以如何使用IDEA來創(chuàng)建java項(xiàng)目呢,這里給大家總結(jié)下,需要的朋友可以參考下2023-08-08使用Java DOM解析器修改XML文件內(nèi)容的操作方法
在Java中,XML文件的解析和修改可以通過多種方法實(shí)現(xiàn),其中DOM(Document Object Model)是一種常用的方式,在本文中,我們將介紹如何使用Java DOM解析器修改XML文件中的內(nèi)容,并給出一個(gè)具體的示例,需要的朋友可以參考下2024-08-08Springboot+SpringSecurity+JWT實(shí)現(xiàn)用戶登錄和權(quán)限認(rèn)證示例
這篇文章主要介紹了Springboot+SpringSecurity+JWT實(shí)現(xiàn)用戶登錄和權(quán)限認(rèn)證示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06Spring Cloud Zuul自定義過濾器的實(shí)現(xiàn)
這篇文章主要介紹了自定義Spring Cloud Zuul過濾器的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03