如何去控制多线程的执行顺序?
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后进先出、优先级等特定顺序执行,但是这种方式也是存在缺点的,就是当一个线程被阻塞时,其它的线程都会受到影响被阻塞,不过依然都会按照自身调度来执行,只是会存在阻塞延迟。