多线程的名词解释就不再赘述了,此篇文章用于讲述多线程关于执行顺序的技术点,默认执行时线程的先后顺序是根据CPU的调度而定的,并不是确定的顺序,当我们直接new一个线程start后每个线程执行的顺序不一定会按照代码定义的顺序进行执行的,直接上代码:
/** * 用于测试的线程类 */ class TestThread implements Runnable { /** * 打印当前线程名称 * * @return void */ @Override public void run() { System.out.println("This thread name is " + Thread.currentThread().getName()); } }
/** * 正常运行(无序) * * @return void */ private static void noSortRun() { new Thread(new TestThread()).start(); new Thread(new TestThread()).start(); new Thread(new TestThread()).start(); new Thread(new TestThread()).start(); new Thread(new TestThread()).start(); }
public static void main(String[] args) throws Exception { System.out.println("正常运行(5次)..."); noSortRun(); }多次运行结果会发现每次执行的顺序都不一样,这里就贴出两次运行结果。
正常运行(5次)...
This thread name is Thread-1
This thread name is Thread-2
This thread name is Thread-0
This thread name is Thread-3
This thread name is Thread-4
正常运行(5次)...
This thread name is Thread-0
This thread name is Thread-2
This thread name is Thread-3
This thread name is Thread-1
This thread name is Thread-4
可以看到每次执行的顺序都不同,并且都不是按照Thread-0、Thread-1、Thread-2、Thread-3、Thread-4这种样式执行。
那么该怎么实现线程间的有序呢?有两种方法,一个是Thread.join(),上洋码子:
/** * join实现有序 * * @return void */ private static void joinRun() throws Exception { Thread t1 = new Thread(new TestThread()); t1.start(); //join()实现线程有序 t1.join(); Thread t2 = new Thread(new TestThread()); t2.start(); t2.join(); Thread t3 = new Thread(new TestThread()); t3.start(); t3.join(); Thread t4 = new Thread(new TestThread()); t4.start(); t4.join(); Thread t5 = new Thread(new TestThread()); t5.start(); }
我们运行这个方法就会发现,无论多少次运行,t1到t5的顺序都不会改变,那么这是为什么嗫?再来看:
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; } } }
这是Thread.join()方法的源码,入参如果不填默认为0,分析得知当mills==0时,会执行isAlive(),我们先猜想一下当mills==0时这段代码的含义,首先执行isAlive()方法,通过名字我们可以猜测是用来判断线程是否活动的,如果活动,则让其等待,究竟是不是呢?继续扒拉洋码子:
/** * Tests if this thread is alive. A thread is alive if it has * been started and has not yet died. * * @return <code>true</code> if this thread is alive; * <code>false</code> otherwise. */ public final native boolean isAlive();
没错,如果当前线程活动则调用wait()方法使主线程等待,我们可以调试下看下
我们可以看到,当前线程的确是main线程,this是子线程,确实如此。
那么第二种方法是什么呢,通过java.util.concurrent下面的Executors.newSingleThreadExecutor()来创建线程池队列,既然是队列那么肯定就能实现有序咯
代码展示:
/** * executors实现有序 * * @return void */ private static void executorRun() { ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(new TestThread()); executorService.submit(new TestThread()); executorService.submit(new TestThread()); executorService.submit(new TestThread()); executorService.submit(new TestThread()); executorService.shutdown(); }