Java 面试题解析:如何使用 ReentrantLock 的条件变量,让多个线程顺序执行?
一. 前言
近日我的一个学生在参加某公司校招面试时,遇到一个多个线程顺序执行的面试题,特意记录下来和大家分享一下,这个题目的具体要求是这样的:假设有 3 个线程 a,b,c,要求三个线程一起进入到就绪态,执行时一定要按照 a-->b-->c 的顺序执行。即使 a 或者 b 线程进入到了阻塞态,也一定会按照 a-->b-->c 的顺序运行线程。请问该如何保证实现这个需求呢?
二. 解决方案
关于这道题,我百度一下网上常见的实现思路,大致有 4 种解决方案:通过 join()方法使当前线程“阻塞”,等待指定线程执行完毕后继续执行;通过倒数计时器 CountDownLatch 实现;通过创建单一化线程池 newSingleThreadExecutor()实现;通过 ReentrantLock 中的条件变量实现;今天我先使用 ReentrantLock 的条件变量来实现这个题目中的需求。
三. 使用 ReentrantLock 条件变量
首先咱们来了解一下,什么是 ReentrantLock 条件变量(Condition)。ReentrantLock 中的条件变量功能,类似于普通 synchronized 的 wait、notify,我们可以使用 Reentrantlock 锁,配合 Condition 对象上的 await()和 signal()或 signalAll()方法,来实现线程间协作。与 synchronized 的 wait 和 notify 不同之处在于,ReentrantLock 中的条件变量可以有多个,可以实现更精细的控制线程。Condition 中常用的方法 API 有如下这些:
<img src="https://picd.zhimg.com/v2-e4b88bb9d3a42fc82bc5f844869fbee3_720w.jpg?source=d16d100b" data-caption="" data-size="normal" data-rawwidth="1024" data-rawheight="514" class="origin_image zh-lightbox-thumb" width="1024" data-original="https://picd.zhimg.com/v2-e4b88bb9d3a42fc82bc5f844869fbee3_720w.jpg?source=d16d100b">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(){
}
public void f2(){
}
public void f3(){
}
}
public class SynchronizedAndReentrantLockDemo {
public static void main(String[] args) {
}
}
代码执行效果如下图:<img src="https://picd.zhimg.com/v2-b170887d15468db541718ae101cb26a6_720w.jpg?source=d16d100b" data-caption="" data-size="normal" data-rawwidth="956" data-rawheight="517" class="origin_image zh-lightbox-thumb" width="956" data-original="https://picd.zhimg.com/v2-b170887d15468db541718ae101cb26a6_720w.jpg?source=d16d100b">
现在我们就会发现,3 个线程已经可以被随意控制了,你会了吗?
四. 后话
如上文所述,让多个线程按顺序执行,网上常见的解决方案有 4 种。但大家要注意的是,面试官出这个题有一个先决条件,“要让所有的线程同时就绪”,所以我们就可以排除使用 join 方法和使用单一化线程池的方案了。那么要想实现这个面试题中的需求,比较靠谱的方法只剩下 ReentrantLock 中的条件变量和使用倒数计时器 CountDownLatch 两种方案了。今天咱们暂时先介绍条件变量的方法,我会在日后的文章中介绍怎样使用 CountDownLatch,让多个线程有序执行,各位敬请期待哦。欢迎关注威哥,天天干货不断!
评论