控制多线程执行顺序

目标:创建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方法时,执行结果是乱序的
在这里插入图片描述
增加join方法后,执行结果是顺序的
在这里插入图片描述
分析join源码

 /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> 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
     *          <i>interrupted status</i> 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  <code>true</code> if this thread is alive;
     *          <code>false</code> 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();
    }
}

执行结果
在这里插入图片描述

这种方式的原理其实就是将线程用排队的方式扔进一个线程池里,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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值