ReentrantLock條件變量使多個(gè)線程順序執(zhí)行
一. 前言
近日一個(gè)學(xué)生在參加某公司校招面試時(shí),遇到一個(gè)多個(gè)線程順序執(zhí)行的面試題,特意記錄下來和大家分享一下,這個(gè)題目的具體要求是這樣的:
假設(shè)有3個(gè)線程 a,b,c,要求三個(gè)線程一起進(jìn)入到就緒態(tài),執(zhí)行時(shí)一定 要 按照 a-->b-->c的順序執(zhí)行 。即使 a或者b線程進(jìn)入 到了 阻塞態(tài),也一定 會(huì) 按照a-->b-->c的順序運(yùn)行線程 。請問該如何保證實(shí)現(xiàn)這個(gè)需求呢?
二. 解決方案
關(guān)于這道題,百度一下網(wǎng)上常見的實(shí)現(xiàn)思路,大致有4種解決方案:
通過join()
方法使當(dāng)前線程“阻塞”,等待指定線程執(zhí)行完畢后繼續(xù)執(zhí)行;
通過倒數(shù)計(jì)時(shí)器CountDownLatch實(shí)現(xiàn);
通過創(chuàng)建單一化線程池 newSingleThreadExecutor()
實(shí)現(xiàn);
通過ReentrantLock 中的條件變量實(shí)現(xiàn);
今天壹哥先使用ReentrantLock 的條件變量來實(shí)現(xiàn)這個(gè)題目中的需求。
三. 使用ReentrantLock 條件變量
首先咱們來了解一下,什么是ReentrantLock 條件變量(Condition)。
ReentrantLock 中的條件變量功能,類似于普通 synchronized 的 wait、notify,我們可以使用Reentrantlock 鎖,配合 Condition 對象上的 await()和 signal()或 signalAll()方法,來實(shí)現(xiàn)線程間協(xié)作。與synchronized的wait和notify不同之處在于,ReentrantLock中的條件變量可以有多個(gè),可以實(shí)現(xiàn)更精細(xì)的控制線程。
Condition中常用的方法API有如下這些:
編輯
ReentrantLock代碼實(shí)現(xiàn):
class ShareDataLock{ // 線程執(zhí)行的條件 1:線程1執(zhí)行 2:線程2執(zhí)行 3:線程3執(zhí)行 int number =1; // 鎖 Lock lock = new ReentrantLock(); // 從鎖中獲得3個(gè)條件變量 Condition condition1 = lock.newCondition(); Condition condition2 = lock.newCondition(); Condition condition3 = lock.newCondition(); // 第一個(gè)線程run之后執(zhí)行的方法 public void f1(){ lock.lock(); try { // 如果條件值不為1 就掛起等待 while(number!=1){ condition1.await(); } // 故意阻塞100毫秒,看看其他的線程會(huì)不會(huì)不再排隊(duì) Thread.sleep(100); System.out.println("------1--------"); // 線程1 執(zhí)行完畢 把變量設(shè)置為2 number = 2; // 喚醒第2個(gè)條件變量 condition2.signal(); } catch (Exception e) { e.printStackTrace(); } finally { // 不管拋沒拋出異常都要解鎖,防止線程死鎖 lock.unlock(); } } public void f2(){ lock.lock(); try { while(number!=2){ condition2.await(); } System.out.println("------2--------"); number = 3; condition3.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void f3(){ lock.lock(); try { while(number!=3){ condition3.await(); } System.out.println("------3--------"); number = 1; condition1.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } } public class SynchronizedAndReentrantLockDemo { public static void main(String[] args) { ShareDataLock shareDataLock = new ShareDataLock(); for (int i = 0; i < 10; i++) { // 3個(gè)線程分別執(zhí)行1,2,3 3個(gè)方法 ,并且同時(shí)就緒 new Thread(()->shareDataLock.f1(),"AA").start(); new Thread(()->shareDataLock.f2(),"bb").start(); new Thread(()->shareDataLock.f3(),"cc").start(); } } }
代碼執(zhí)行效果如下圖:
現(xiàn)在我們就會(huì)發(fā)現(xiàn),3個(gè)線程已經(jīng)可以被隨意控制了,你會(huì)了嗎?
四. 后話
如上文所述,讓多個(gè)線程按順序執(zhí)行,網(wǎng)上常見的解決方案有4種。但大家要注意的是,面試官出這個(gè)題有一個(gè)先決條件,“要讓所有的線程同時(shí)就緒 ” ,所以我們就可以排除使用join方法和使用單一化線程池的方案了。那么要想實(shí)現(xiàn)這個(gè)面試題中的需求,比較靠譜的方法只剩下ReentrantLock 中的條件變量和使用倒數(shù)計(jì)時(shí)器CountDownLatch兩種方案了 。
今天咱們暫時(shí)先介紹條件變量的方法,會(huì)在日后的文章中介紹怎樣使用CountDownLatch , 讓多個(gè)線程有序執(zhí)行.
以上就是ReentrantLock條件變量使多個(gè)線程順序執(zhí)行的詳細(xì)內(nèi)容,更多關(guān)于ReentrantLock多個(gè)線程順序執(zhí)行的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
springboot2中HikariCP連接池的相關(guān)配置問題
這篇文章主要介紹了springboot2中HikariCP連接池的相關(guān)配置問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12詳解spring boot實(shí)現(xiàn)websocket
這篇文章主要介紹了詳解spring boot實(shí)現(xiàn)websocket,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06詳解Springboot-MyBatis配置-配置端口號(hào)與服務(wù)路徑(idea社區(qū)版2023.1.4+apache-mav
這篇文章主要介紹了Springboot-MyBatis配置-配置端口號(hào)與服務(wù)路徑(idea社區(qū)版2023.1.4+apache-maven-3.9.3-bin),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07利用Kafka動(dòng)態(tài)調(diào)整topic分區(qū)partition
這篇文章主要介紹了利用Kafka動(dòng)態(tài)調(diào)整topic分區(qū)partition問題,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12