故事
上周一位同学在面试中遇到了这么一道问题:
有三个线程T1、T2、T3,如何保证顺序执行?
常规操作,启动三个线程,让其执行。
public class ThreadDemo {
public static void main(String[] args) {
final Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程1");
}
});
final Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程2");
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程3");
}
});
t1.start();
t2.start();
t3.start();
}
}
登录后复制
运行结果:
线程2
线程1
线程3
登录后复制
调用三个线程的start方法,很明显是按照顺序调用的,但是每次运行出来的结果,基本上都不相同,随机性特别强。
怎么办呢?下面我们使用四种方案来实现。
方案一
我们可以利用Thread中的join方法解决线程顺序问题,下面我们来简单介绍一下join方法。
官方介绍:
Waits for this thread to die.
等待这个线程结束,也就是说当前线程等待这个线程结束后再继续执行 。
join()
方法是Thread
中的一个public
方法,它有几个重载版本:
join()
join(long millis)
//参数为毫秒join(long millis,int nanoseconds)
//第一参数为毫秒,第二个参数为纳秒
join()方法实际是利用了wait()
方法(wait方法是Object中的),只不过它不用等待notify()/notifyAll()
,且不受其影响。
它结束的条件是:
- 等待时间到
- 目标线程已经run完(通过
isAlive()
方法来判断)
下面大致看看器源码:
public final void join() throws InterruptedException {
//调用了另外一个有参数的join方法
join(0);
}
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis t2.start())
.thenRun(()->t3.start());
}
static class Work implements Runnable{
@Override
public void run() {
System.out.println("执行 : " + Thread.currentThread().getName());
}
}
}
登录后复制
运行结果:
执行 : 线程1
执行 : 线程2
执行 : 线程3
登录后复制
到此,我们就使用CompletableFuture
实现了多个线程顺序执行的问题。
总结
关于多个线程顺序执行,不管是对于面试,还是工作,关于多线程顺序执行的解决方案都是非常有必要掌握的。也希望下次面试官再问:多线程顺序执行问题的时候,你的表情应该是这样的: