经常看见面试题:有三个线程T1,T2,T3,有什么方法可以确保它们按顺序执行。今天手写测试了一下,下面贴出目前想到的3种实现方式

说明:这里在线程中我都用到了sleep方法,目的是更容易发现问题。之前看到其他人写的错误代码,测试了好多遍没测试出问题,比如下面这种错误方式

错误方式(最开始测试,一直都是正确的输出顺序,放开了sleep 注释部分,输出顺序直接不是  t3,t2,t1。错误显而易见)

        public static void main(String[] args) {

            final Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println("t1");
}
});
final Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
// Thread.sleep(50);
//引用t1线程,等待t1线程执行完
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t2");
}
},"t2");
final Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
try {
// Thread.sleep(10);
//引用t2线程,等待t2线程执行完
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("t3");
}
});
t1.start();
t2.start();
t3.start();

下面说明一下正确的实现方式

第一种方式:顺序在线程中创建实例(最容易想到的办法)。

public class TestTwo {
static TestTwo t=new TestTwo();
class T1 extends Thread{
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//T1线程中要处理的东西
System.out.println("T1线程执行")
}
} class T2 extends Thread{
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
//T2线程中要处理的东西
System.out.println("T2线程执行");
t.new T1().start();
}
} class T3 extends Thread{
@Override
public void run() {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
//T3线程中要处理的东西
System.out.println("T3线程执行");
t.new T2().start();
}
} public static void main(String[] args) {
t.new T3().start();
       //打印结果如下:
             //T3线程执行
        //T2线程执行

              //T1线程执行

        }

}

第二种方式:看到有人说运用单个线程池(SingleThreadExecutor)来实现,确切的说这里不太符合,从打印结果看出,其实我们是在一个线程里,执行了三个任务。

             Thread t1 = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " run 1");
}
}, "T1");
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " run 2");
}
}, "T2");
Thread t3 = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " run 3");
}
}, "T3"); //三个线程顺序执行 第一种方案,单个线程池 顺序放入执行队列中
ExecutorService executor = Executors.newSingleThreadExecutor(); executor.submit(t3);
executor.submit(t2);
executor.submit(t1);
executor.shutdown();
//输出结果如下:
// pool-1-thread-1 run 3
// pool-1-thread-1 run 2
// pool-1-thread-1 run 1

第三种方式:运用线程的  join   方法来实现

join方法实现原理和参数说明参照这篇博客,多余的CP工作就不用了:https://www.cnblogs.com/lcplcpjava/p/6896904.html

public class Testt {

    static Testt t=new Testt();

    class T1 extends Thread{
public T1(String name){
super(name);
}
@Override
public void run() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
//T3线程中要处理的东西
System.out.println("T1线程执行");
for(int i=0;i<10;i++){
System.out.println(this.getName() + ":" + i);
}
}
} class T2 extends Thread{
public T2(String name){
super(name);
}
@Override
public void run() {
//T3线程中要处理的东西
System.out.println("T2线程执行");
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
for(int i=0;i<10;i++){
System.out.println(this.getName() + ":" + i);
}
}
} class T3 extends Thread{
public T3(String name){
super(name);
}
@Override
public void run() {
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
//T3线程中要处理的东西
System.out.println("T3线程执行");
for(int i=0;i<10;i++){
System.out.println(this.getName() + ":" + i);
}
}
} public static void main(String[] args) {
try {
T3 t3= t.new T3("T3");
t3.start();//启动t3线程
t3.join();//阻塞主线程,执行完t3再返回 T2 t2= t.new T2("T2");
t2.start();//启动t3线程
t2.join();//阻塞主线程,执行完t3再返回 T1 t1= t.new T1("T1");
t1.start();//启动t3线程
t1.join();//阻塞主线程,执行完t3再返回 // T3线程执行
// T3:0
// T3:1
// T3:2
// T3:3
// T3:4
// T3:5
// T3:6
// T3:7
// T3:8
// T3:9
// T2线程执行
// T2:0
// T2:1
// T2:2
// T2:3
// T2:4
// T2:5
// T2:6
// T2:7
// T2:8
// T2:9
// T1线程执行
// T1:0
// T1:1
// T1:2
// T1:3
// T1:4
// T1:5
// T1:6
// T1:7
// T1:8
// T1:9
} catch (InterruptedException e) {
e.printStackTrace();
}
}

参考博客:https://blog.csdn.net/yuwinter/article/details/78772933

  注意这里的博客写出的方法有错误:这里的join方法要对同一个实例,不然没有作用。具体可以参考上面的链接查看join实现原理。

//        try {
// t.new T3().start();//启动t3线程
// t.new T3().join();//阻塞主线程,执行完t3再返回
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// try {
// t.new T1().start();//启动t1线程
// t.new T1().join();//阻塞主线程,执行完t1再返回
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
//
// try {
// t.new T2().start();//启动t2线程
// t.new T2().join();//阻塞主线程,执行完t2再返回
// } catch (InterruptedException e) {
// e.printStackTrace();
// }

  以上就是 三个线程的顺序实现方式介绍,看了其他的博客潦草写的实现,不假思索的错误实现,希望各位自己在写东西的时候多加思考和论证!以上若有错误,欢迎评论指正

三个线程T1,T2,T3.保证顺序执行的三种方法的更多相关文章

  1. 有三个线程T1 T2 T3,如何保证他们按顺序执行-转载

    T3先执行,在T3的run中,调用t2.join,让t2执行完成后再执行t3 在T2的run中,调用t1.join,让t1执行完成后再让T2执行 public class Test { // 1.现在 ...

  2. 有三个线程T1 T2 T3,如何保证他们按顺序执行

    T3先执行,在T3的run中,调用t2.join,让t2执行完成后再执行t3 在T2的run中,调用t1.join,让t1执行完成后再让T2执行 public class JoinTest {     ...

  3. Java:现有线程T1/T2/T3,如何确保T1执行完成之后执行T2,T3在T2执行完成之后执行。

    要实现多个线程执行完成先后,就要知道如何实现线程之间的等待,java线程等待实现是join.java的jdk中join方法实现如下: public final synchronized void jo ...

  4. Java-JUC(零):Java:现有线程T1/T2/T3,如何确保T1执行完成之后执行T2,T3在T2执行完成之后执行。

    要实现多个线程执行完成先后,就要知道如何实现线程之间的等待,java线程等待实现是join.java的jdk中join方法实现如下: public final synchronized void jo ...

  5. join控制线程的执行循序 T1 -> T2 -> T3

    /** * 控制线程的执行循序 T1 -> T2 -> T3 * join实现 */ public static void join(){ Thread t1 = new Thread(( ...

  6. 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行?

    Thread t1 = new Thread(new T1()); Thread t2 = new Thread(new T2()); Thread t3 = new Thread(new T3()) ...

  7. java 多线程,T1 T2 T3 顺序执行

    一.程序设计 1.抽象公共类PublicThread,具有先前线程属性previousThread.父类为Thread 2.在PublicThread的run()方法中判断previousThread ...

  8. JS基础入门篇( 三 )—使用JS获取页面中某个元素的4种方法以及之间的差别( 一 )

    1.使用JS获取页面中某个元素的4种方法 1.通过id名获取元素 document.getElementById("id名"); 2.通过class名获取元素 document.g ...

  9. js中页面加载完成后执行的几种方法及执行顺序

    在js和jquery使用中,经常使用到页面加载完成后执行某一方法.通过整理,大概是五种方式(其中有的只是书写方式不一样). 1:使用jQuery的$(function){}; 2:使用jquery的$ ...

随机推荐

  1. FPGA跨时钟域握手信号的结构

    FPGA跨时钟数据传输,是我们经常遇到的问题的,下面给出一种跨时钟握手操作的电路结构.先上图 先对与其他人的结构,这个结构最大的特点是使用 req 从低到高或者高到低的变化 来表示DIN数据有效并开始 ...

  2. 背水一战 Windows 10 (97) - 选取器: CachedFileUpdater

    [源码下载] 背水一战 Windows 10 (97) - 选取器: CachedFileUpdater 作者:webabcd 介绍背水一战 Windows 10 之 选取器 CachedFileUp ...

  3. PHP LDAP 目录协议函数库

    在 LDAP 的协议之中,很像硬盘目录结构或倒过来的树状结构.LDAP 的根就是全世界,第一级是属于国别 (countries) 性质的层级,之后可能会有公司 (organization) 的层级,接 ...

  4. 教你一招用 IDE 编程提升效率的骚操作!

    阅读本文大概需要 3 分钟. IDEA 有个很牛逼的功能,那就是后缀补全(不是自动补全),很多人竟然不知道这个操作,还在手动敲代码. 这个功能可以使用代码补全来模板式地补全语句,如遍历循环语句(for ...

  5. QMQ去哪儿网-mq中间件(启动失败)

    简介 去哪儿网近日宣布开源其内部广泛使用的消息中间件 QMQ .QMQ 自 2012 年诞生以来在去哪儿网所有业务场景中广泛的应用,包括跟交易息息相关的订单场景: 也包括报价搜索等高吞吐量场景.目前在 ...

  6. 用excel记录测试bug问题总结

    前几天与开发在讨论问题的时候,开发提了一个问题,说是已经解决的问题,能否用excel表格总结一下,问了一下原因,感觉想法很好,就总结了一下. 在上家公司的时候,提交bug用的是mantis,现在是禅道 ...

  7. deepin卸载mysql并安装设置mysql5.7

    mysql完全卸载以及安全安装 完全卸载 sudo apt purge mysql-* sudo rm -rf /etc/mysql/ /var/lib/mysql sudo apt autoremo ...

  8. Git+Hexo搭建个人博客详细过程

    通过Git+Hexo搭建的个人博客地址:https://liangh.top/ 1.安装Node.js.配置好Node.js环境.安装Git和配置好Git环境,打开cmd命令行,成功界面如下 2.安装 ...

  9. 剑指offer【04】- 重建二叉树(java)

    题目:重建二叉树 考点:树 题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6, ...

  10. 图片base64上传时可能遇到的问题

    base64上传图片时服务器接到的值可能会丢失字符串 解决方法如下:(分为单个上传和多个上传) <?php $BASE_DIR = "../"; //文件上传 $img = ...