ReentrantLock條件變量使多個線程順序執(zhí)行
一. 前言
近日一個學(xué)生在參加某公司校招面試時,遇到一個多個線程順序執(zhí)行的面試題,特意記錄下來和大家分享一下,這個題目的具體要求是這樣的:
假設(shè)有3個線程 a,b,c,要求三個線程一起進(jìn)入到就緒態(tài),執(zhí)行時一定 要 按照 a-->b-->c的順序執(zhí)行 。即使 a或者b線程進(jìn)入 到了 阻塞態(tài),也一定 會 按照a-->b-->c的順序運(yùn)行線程 。請問該如何保證實(shí)現(xiàn)這個需求呢?
二. 解決方案
關(guān)于這道題,百度一下網(wǎng)上常見的實(shí)現(xiàn)思路,大致有4種解決方案:
通過join()方法使當(dāng)前線程“阻塞”,等待指定線程執(zhí)行完畢后繼續(xù)執(zhí)行;
通過倒數(shù)計(jì)時器CountDownLatch實(shí)現(xiàn);
通過創(chuàng)建單一化線程池 newSingleThreadExecutor()實(shí)現(xiàn);
通過ReentrantLock 中的條件變量實(shí)現(xiàn);
今天壹哥先使用ReentrantLock 的條件變量來實(shí)現(xiàn)這個題目中的需求。
三. 使用ReentrantLock 條件變量
首先咱們來了解一下,什么是ReentrantLock 條件變量(Condition)。
ReentrantLock 中的條件變量功能,類似于普通 synchronized 的 wait、notify,我們可以使用Reentrantlock 鎖,配合 Condition 對象上的 await()和 signal()或 signalAll()方法,來實(shí)現(xiàn)線程間協(xié)作。與synchronized的wait和notify不同之處在于,ReentrantLock中的條件變量可以有多個,可以實(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個條件變量
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
// 第一個線程run之后執(zhí)行的方法
public void f1(){
lock.lock();
try {
// 如果條件值不為1 就掛起等待
while(number!=1){
condition1.await();
}
// 故意阻塞100毫秒,看看其他的線程會不會不再排隊(duì)
Thread.sleep(100);
System.out.println("------1--------");
// 線程1 執(zhí)行完畢 把變量設(shè)置為2
number = 2;
// 喚醒第2個條件變量
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個線程分別執(zhí)行1,2,3 3個方法 ,并且同時就緒
new Thread(()->shareDataLock.f1(),"AA").start();
new Thread(()->shareDataLock.f2(),"bb").start();
new Thread(()->shareDataLock.f3(),"cc").start();
}
}
}
代碼執(zhí)行效果如下圖:

現(xiàn)在我們就會發(fā)現(xiàn),3個線程已經(jīng)可以被隨意控制了,你會了嗎?
四. 后話
如上文所述,讓多個線程按順序執(zhí)行,網(wǎng)上常見的解決方案有4種。但大家要注意的是,面試官出這個題有一個先決條件,“要讓所有的線程同時就緒 ” ,所以我們就可以排除使用join方法和使用單一化線程池的方案了。那么要想實(shí)現(xiàn)這個面試題中的需求,比較靠譜的方法只剩下ReentrantLock 中的條件變量和使用倒數(shù)計(jì)時器CountDownLatch兩種方案了 。
今天咱們暫時先介紹條件變量的方法,會在日后的文章中介紹怎樣使用CountDownLatch , 讓多個線程有序執(zhí)行.
以上就是ReentrantLock條件變量使多個線程順序執(zhí)行的詳細(xì)內(nèi)容,更多關(guān)于ReentrantLock多個線程順序執(zhí)行的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Mybatis-Plus根據(jù)自定義注解實(shí)現(xiàn)自動加解密的示例代碼
我們把數(shù)據(jù)存到數(shù)據(jù)庫的時候,有些敏感字段是需要加密的,從數(shù)據(jù)庫查出來再進(jìn)行解密,如果我們使用的是Mybatis框架,那就跟著一起探索下如何使用框架的攔截器功能實(shí)現(xiàn)自動加解密吧,需要的朋友可以參考下2024-06-06
SpringBoot?項(xiàng)目打成?jar后加載外部配置文件的操作方法
這篇文章主要介紹了SpringBoot?項(xiàng)目打成?jar后加載外部配置文件的操作方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
Java中BigDecimal類與int、Integer使用總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中BigDecimal類與int、Integer使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07
mybatisplus實(shí)現(xiàn)自動創(chuàng)建/更新時間的項(xiàng)目實(shí)踐
Mybatis-Plus提供了自動填充功能,可以通過實(shí)現(xiàn)MetaObjectHandler接口來實(shí)現(xiàn)自動更新時間的功能,本文就來介紹一下mybatisplus實(shí)現(xiàn)自動創(chuàng)建/更新時間的項(xiàng)目實(shí)踐,感興趣的可以了解下2024-01-01
java模擬ajax訪問另一個項(xiàng)目的controller代碼實(shí)例
今天小編就為大家分享一篇關(guān)于java模擬ajax訪問另一個項(xiàng)目的controller代碼實(shí)例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-03-03

