使用ReentrantLock中的条件变量让多个线程顺序执行
创始人
2024-01-25 14:17:01
0

一. 前言

近日壹哥的一个学生在参加某公司校招面试时,遇到一个多个线程顺序执行的面试题,特意记录下来和大家分享一下,这个题目的具体要求是这样的:

假设有3个线程 a,b,c,要求三个线程一起进入到就绪态,执行时一定按照 a-->b-->c的顺序执行。即使a或者b线程进入到了阻塞态,也一定按照a-->b-->c的顺序运行线程。请问该如何保证实现这个需求呢?

二. 解决方案

关于这道题,壹哥百度一下网上常见的实现思路,大致有4种解决方案:

  1. 通过join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行;
  2. 通过倒数计时器CountDownLatch实现;
  3. 通过创建单一化线程池 newSingleThreadExecutor()实现;
  4. 通过ReentrantLock 中的条件变量实现;

今天壹哥先使用ReentrantLock 的条件变量来实现这个题目中的需求。

三. 使用ReentrantLock 条件变量

首先咱们来了解一下,什么是ReentrantLock 条件变量(Condition)。

ReentrantLock 中的条件变量功能,类似于普通 synchronized 的 wait、notify,我们可以使用Reentrantlock 锁,配合 Condition 对象上的 await()和 signal()或 signalAll()方法,来实现线程间协作。与synchronized的wait和notify不同之处在于,ReentrantLock中的条件变量可以有多个,可以实现更精细的控制线程。

Condition中常用的方法API有如下这些:

ReentrantLock代码实现:

class ShareDataLock{// 线程执行的条件 1:线程1执行 2:线程2执行 3:线程3执行int number =1;// 锁Lock lock = new ReentrantLock();// 从锁中获得3个条件变量Condition condition1 = lock.newCondition();Condition condition2 = lock.newCondition();Condition condition3 = lock.newCondition();// 第一个线程run之后执行的方法public void f1(){lock.lock();try {// 如果条件值不为1 就挂起等待while(number!=1){condition1.await();}// 故意阻塞100毫秒,看看其他的线程会不会不再排队Thread.sleep(100);System.out.println("------1--------");// 线程1 执行完毕 把变量设置为2number = 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个线程分别执行1,2,3 3个方法 ,并且同时就绪new Thread(()->shareDataLock.f1(),"AA").start();new Thread(()->shareDataLock.f2(),"bb").start();new Thread(()->shareDataLock.f3(),"cc").start();}}
}

代码执行效果如下图:

 现在我们就会发现,3个线程已经可以被随意控制了,你会了吗?

四. 后话

如上文所述,让多个线程按顺序执行,网上常见的解决方案有4种。但大家要注意的是,面试官出这个题有一个先决条件,“要让所有的线程同时就绪,所以我们就可以排除使用join方法和使用单一化线程池的方案了。那么要想实现这个面试题中的需求,比较靠谱的方法只剩下ReentrantLock 中的条件变量和使用倒数计时器CountDownLatch两种方案了。今天咱们暂时先介绍条件变量的方法,壹哥会在日后的文章中介绍怎样使用CountDownLatch让多个线程有序执行,敬请各位粉丝儿们继续期待哦。关注Java架构栈,天天干货都不断哦。

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...