控制多线程执行顺序

目标:创建4个线程分别为thread1,thread2,thread3,thread4让这三个线程依次执行。

方法一:join

public class ThreadSequence {
    //线程1 ----------------------》
    static Thread thread1 =  new Thread(()->{
        System.out.println(Thread.currentThread().getName()+"启动了------》");
    },"线程t1");
    //线程2 ----------------------》
    static Thread thread2 = new Thread(()->{
        System.out.println(Thread.currentThread().getName()+"启动了------》");
    },"线程t2");

    //线程3 ----------------------》
    static Thread thread3 = new Thread(()->{
        System.out.println(Thread.currentThread().getName()+"启动了------》");
    },"线程t3");

    //线程4 ----------------------》
    static Thread thread4 = new Thread(()->{
        System.out.println(Thread.currentThread().getName()+"启动了------》");
    },"线程t4");


    public static void main(String[] args) throws Exception{
        /*代码解释:
        * 程序main线程中调用thread1线程的join方法,则main线程会放弃CPU,返回给thread1,直到thread1执行完毕。
        * 所以是thread1线程执行完后,才到主线程执行,相当于在main线程中同步thread1线程,thread1执行完了,main线程才有执行的机会
        * */
        thread1.start();
        thread1.join();//join代表让主线程即main线程,等待子线程运行结束后才继续执行
        thread2.start();
        thread2.join();
        thread3.start();
        thread3.join();
        thread4.start();
        thread4.join();
    }
}

未添加join方法时,执行结果是乱序的
控制多线程执行顺序_第1张图片
增加join方法后,执行结果是顺序的
控制多线程执行顺序_第2张图片
分析join源码

 /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * 

This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances. * * @param millis * the time to wait in milliseconds * * @throws IllegalArgumentException * if the value of {@code millis} is negative * * @throws InterruptedException * if any thread has interrupted the current thread. The * interrupted status of the current thread is * cleared when this exception is thrown. */ 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; } } } /** * Tests if this thread is alive. A thread is alive if it has * been started and has not yet died. * * @return true if this thread is alive; * false otherwise. */ public final native boolean isAlive();

源码中的参数millis默认值是0,从英文注释翻译后可以找到,0秒意味着永远等待,也就是thread1执行不完,那主线程你就要一直等着,一直wait,而代码中wait方法其实就是属于Object的方法,负责线程的休眠等待,当main主线程调用thread1.join的时候,main主线程会获得线程对象thread1的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main主线程 ,比如退出后。这就意味着main 线程调用thread1.join时,必须能够拿到线程thread1对象的锁。

这里有一个**isAlive()**方法很重要。判断当前线程是否处于活动状态。活动状态就是线程启动且尚未终止,比如正在运行或准备开始运行。

所以从代码上看,如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的,将直接继续向下执行。

在Object.java中,wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。

所以Join()主要就是通过wait()方法来实现这个目的的。

方法二:ExecutorService()的newSingleThreadExecutor()

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorServiceSequence {
    static ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
    //线程1 ----------------------》
    static Thread thread1 =  new Thread(()->{
        System.out.println("启动了线程t1------》");
    });
    //线程2 ----------------------》
    static Thread thread2 = new Thread(()->{
        System.out.println("启动了线程t2------》");
    });

    //线程3 ----------------------》
    static Thread thread3 = new Thread(()->{
        System.out.println("启动了线程t3------》");
    });

    //线程4 ----------------------》
    static Thread thread4 = new Thread(()->{
        System.out.println("启动了线程t4------》");
    });

    public static void main(String[] args) {
        executorService.submit(thread1);
        executorService.submit(thread2);
        executorService.submit(thread3);
        executorService.submit(thread4);
        executorService.shutdown();
    }
}

执行结果
控制多线程执行顺序_第3张图片

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

参考文章
https://www.cnblogs.com/panda001/p/12363532.html
https://www.jianshu.com/p/481c01528bdb
https://www.cnblogs.com/xieshengdev/p/10082787.html

你可能感兴趣的:(线程,多线程,thread,java)