前几天有一位同事在阿里一面的时候被问到这么一个多线程问题:如何保证多个线程的顺序执行。当时他没有回答上来,所以为了避免大家以后遇到同样的面试题还是回答不上来,今天我们就来分析解答下这个问题。

问题缘由

由于线程执行是靠CPU分时间片来处理的,那么多个线程执行的时候,如果不加限制,那么线程的执行顺序是无法保证的。如下源码:

public class OrderThreadMain {    public static void main(String[] args) {       Thread A =  new Thread(()->{           System.out.println("A");       });        Thread B =  new Thread(()->{            System.out.println("B");        });        Thread C =  new Thread(()->{            System.out.println("C");        });        A.start();        B.start();        C.start();    }}

A B C三个线程同时启动,最后的执行结果不是每次都顺序输出 A B C,而是每次运行结果都是不一样的。有可能输出A B C,有也可能输出 B A C,是无法保证线程的顺序执行的。

join方式实现

join方式即使用Thread.join方法来实现。Thread.join含义当前线程需要等待previousThread线程终止之后才从thread.join返回。简单来说,就是线程没有执行完之前,会一直阻塞在join方法处。

join方式实现方式存在两种:主线程join和执行线程join。下面我们依次来分析一下:

1.主线程join

public class OrderThreadMain {    public static void main(String[] args) throws InterruptedException {       Thread A =  new Thread(()->{           System.out.println("A");       });        Thread B =  new Thread(()->{            System.out.println("B");        });        Thread C =  new Thread(()->{            System.out.println("C");        });        A.start();        //等待A线程执行完在启动B线程        A.join();        B.start();        //等待B线程执行完在启动C线程        B.join();        C.start();        C.join();    }}//输出结果://A //B//C

上面源码就是主线程join的实现方式,其原理就是保证执行线程执行完毕再start后续线程,从而实现多个线程的顺序执行。

2.执行线程join

package com.example.demo.concurrent;import java.util.concurrent.Executors;public class OrderThreadMain {    static class TestThread extends Thread{        private Thread beforeThread;        private String str;        TestThread(Thread beforeThread, String str){            this.beforeThread = beforeThread;            this.str = str;        }        @Override        public void run() {            if (beforeThread != null){                try {                    beforeThread.join();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            System.out.println(str);        }    }    public static void main(String[] args) {        TestThread A = new TestThread(null, "A");        TestThread B = new TestThread(A, "B");        TestThread C = new TestThread(B, "C");        A.start();        B.start();        C.start();    }}//输出结果://A //B//C

上面源码就是执行线程join的实现方式,其原理就是通过传入beforeThread(在这个线程执行前需要执行完的线程对象)来保证多个线程顺序执行。

Thread.join源码实现:

public final void join() throws InterruptedException {  join(0);}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源码可以知道,Thread.join原理其实很简单,就是如果线程还未执行完成就一直轮训等待,执行完成则结束轮训,继续执行后续代码。

Executors.newSingleThreadExecutor方式实现

Executors.newSingleThreadExecutor是一种特殊的线程池实现,它是一个单线程的线程池,核心线程数和最大线程数都为1,相当于串行执行,所以可以通过它来实现多个线程顺序执行。

注:如果大家对线程池不是很了解可以阅读作者之前一篇关于线程池的文章:

阿里P8大佬总结:Java线程池详解,看了你就懂

public class OrderThreadMain {    public static void main(String[] args) {        Runnable A = new Runnable() {            @Override            public void run() {                System.out.println("A");            }        };        Runnable B = new Runnable() {            @Override            public void run() {                System.out.println("B");            }        };        Runnable C = new Runnable() {            @Override            public void run() {                System.out.println("C");            }        };        ExecutorService executorService =  Executors.newSingleThreadExecutor();      //按顺序提交任务 可以保证多个线程按提交顺序执行        executorService.submit(A);        executorService.submit(B);        executorService.submit(C);    }}//输出结果://A //B//C

上面源码就是Executors.newSingleThreadExecutor的实现方式,只要保证任务时按顺序提交,那么就能保证多个线程任务的顺序执行。

END

笔者是一位热爱互联网、热爱互联网技术、热于分享的年轻人,如果您跟我一样,我愿意成为您的朋友,分享每一个有价值的知识给您。喜欢作者的同学,点赞+转发+关注哦!

点赞+转发+关注,私信作者“读书笔记”即可获得BAT大厂面试资料、高级架构师VIP视频课程等高质量技术资料。

BAT等一线互联网面试资料和VIP高级架构师视频

多个for语句嵌套执行顺序_阿里真实面试题解析之实现多个线程顺序执行的几种方式...相关推荐

  1. 按照顺序执行_问一个多线程的问题:如何才能保证线程有序执行?

    面试的时候你是否经常被问到这样的问题: 你一般通过什么方式去控制线程的执行顺序? 碰到这样的问题,我的内心其实是很抵触的! 开什么玩笑?我怎么会控制它呢?我为什么要控制它? 其实不用慌,这个问题并不难 ...

  2. javafx应用启动自动执行函数_一张图,理顺 Spring Boot应用在启动阶段执行代码的几种方式...

    前言 有时候我们需要在应用启动时执行一些代码片段,这些片段可能是仅仅是为了记录 log,也可能是在启动时检查与安装证书 ,诸如上述业务要求我们可能会经常碰到 Spring Boot 提供了至少 5 种 ...

  3. ios 应用和电脑共享文件夹_堪比AirDrop,苹果 iPhone与Windows电脑互传文件的三种方式...

    如果你是苹果全家桶用户,一定会对 「AirDrop(隔空投送)」 功能赞誉有加,使用 AirDrop 可以在 iPhone 与 MacBook.iPad 等设备之间快速传递照片.视频或文件. 遗憾的是 ...

  4. python表达式中可以控制运算的优先顺序_在Python表达式中可以使用_______控制运算的优先顺序。...

    [填空题]Python中的大部分对象均为不可变对象,例如___________________________等,_ __________________________________等则为可变对象 ...

  5. mysql连接的时候里执行命令_在Bash里使用交互式命令连接MySQL数据库,并执行一次查询...

    首先,我们是使用一台Linux终端来连接远程服务器上的MySql数据库,所以操作系统上需要安装客户端.# yum install mysql 注意,书写安装的是MySQL, 可实际安装的确是Maria ...

  6. c++ sleep函数_我们如何在C,C ++中控制/安排线程的执行?

    前两个示例在C中,最后一个在C ++中.在我的第一种方法中,我使用3个互斥锁和3个条件变量.通过以下示例,您可以在C和C ++中计划或控制任意数量的线程.首先,看看下面的第一个帖子.这里锁定了互斥锁l ...

  7. 博图14软件安装顺序_请教关于博途软件中各个部分的安装顺序和注意事项。

    电脑上装了一个TIA V13,第一次使用博途,以为装好一个就行了,后发才发现还有其他的也要装,现在准备重新安装一下,最好安装齐全点,之前的是 STEP 7 Professional V13 SP1 U ...

  8. 批处理定时执行任务_如何让你的西门子Wincc V14,每天定时自动执行某任务

    全文约700字,通读约3分钟 一:如何让你的VB脚本后台默默运行 二:实例:计划任务定时触发"项目锁定脚本检测"后台默默运行 三:问题拓展:如何让你的脚本时刻保持运行 一:如何让你 ...

  9. python 线程通信的几种方式_进程间通信和线程间通信的几种方式

    进程 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执行实体:在当代 ...

最新文章

  1. 基于双门限法的端点检测
  2. 机器学习-第六章 支持向量机(SVM)
  3. java父线程子线程
  4. php绑定变量,php动态绑定变量的用法
  5. HBA driver for linux
  6. the title and note has maintained the same text type
  7. luogu1355 神秘大三角
  8. 玩转git-flow工作流-分支解析
  9. .net core 正则表达式 获取 等号后面的值_Python3 正则表达式
  10. hdu 2034 - 集合操作
  11. 【报告分享】与AI共进,智胜未来:智能金融联合报告-埃森哲百度.pdf
  12. 信息技术是一把双刃剑,如何掌控好这柄剑?
  13. ASM磁盘配置(udev)
  14. servlet 跳转到 jsp 乱码解决
  15. 为什么说《千与千寻》是一部优秀的职场电影
  16. 远程视频监控必备专业知识
  17. 零基础学鸿蒙编程-UI控件_DatePicker
  18. springboot 集成 RabbitMQ confirm 确认模式和 return 回退模式以及Consumer Ack模式
  19. 顶级科学家是哲学家,顶级investor是哲学家
  20. 公司企业网站SEO优化详解教程

热门文章

  1. python-字符串方法
  2. Leetcode--2. 两数相加
  3. python 运维包_基础入门_Python-模块和包.运维开发中__import__动态导入最佳实践?
  4. python实现栈的操作入站出站查找元素等_Python实现的栈(Stack)
  5. linux基础操作与实践,Linux操作系统基础与实践
  6. python爬取网页新闻_Python爬取新闻网数据
  7. usb转232线驱动_为什么越来越多人用USB,却不用RS232?USB有什么好?
  8. C++将01数组转换为二进制对应的数值
  9. 逻辑回归实现多分类任务(python+TensorFlow+mnist)
  10. OpenCV与图像处理学习八——图像边缘提取(Canny检测代码)