如何去控制多线程的执行顺序?
join方式
我们直接通过在每个Thread对象后面使用join方法就可以实现线程的顺序执行,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class ThreadDemo extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName()); }
public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 4; i++) { ThreadDemo threadDemo = new ThreadDemo(); threadDemo.start(); threadDemo.join(); } System.out.println("我是主线程"); } }
|
多次执行结果都为下面这种情况:

用join方法来保证线程顺序,其实就是让main这个主线程等待子线程结束,然后主线程再执行接下来的其他线程任务,点进去join方法我们可以了解的更透彻:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0;
if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); }
if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
|
源码中的参数millis默认值是0,从英文注释翻译后可以找到,0秒意味着永远等待,也就是threadDemo执行不完,那主线程你就要一直等着,一直wait,而代码中wait方法其实就是属于Object的方法,负责线程的休眠等待,当主线程调用threadDemo.join的时候,主线程会获得线程对象threadDemo的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒主线程。这就意味着主线程调用threadDemo.join时,必须能够拿到threadDemo线程对象的锁。
ExecutorService方式
首先看一下代码,我们如何通过这种方式实现线程顺序执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;
public class ThreadDemo2 { static ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void main(String[] args) { for (int i = 0; i < 5; i++) { int temp = i; Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("thread" + temp); } }); executorService.submit(thread); } executorService.shutdown(); } }
|
最终的多次执行结果均为有序的,如下图:

解释一下,这种方式的原理其实就是将线程用排队的方式扔进一个线程池里,让所有的任务以单线程的模式,按照FIFO先进先出、LIFO后进先出、优先级等特定顺序执行,但是这种方式也是存在缺点的,就是当一个线程被阻塞时,其它的线程都会受到影响被阻塞,不过依然都会按照自身调度来执行,只是会存在阻塞延迟。