经常看见面试题:有三个线程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. spring boot 入门及示例

    需要环境:eclipse4.7.3 + jdk1.8 +maven3.6.1 + tomcat(web需要) spring boot官网介绍:https://spring.io/guides/gs/s ...

  2. vue2入坑随记(一)-- 初始全家桶

    都说Vue2简单,上手容易,但小马过河,自己试了才晓得,除了ES6语法和webpack的配置让你感到陌生,重要的是思路的变换,以前随便拿全局变量和修改dom的锤子不能用了,变换到关注数据本身.vue的 ...

  3. 如何推翻JAVA的统治地位?

    “java越来越过份了.”php狠狠的说,他转头看着C:“C哥,您可是前辈,java最近砸了我不少场子,您老再不出来管管,我怕他眼里就没有您了啊.” C哥吸烟,慢慢的说:“年轻人不要着急,java的根 ...

  4. Java常用的经典排序算法:冒泡排序与选择排序

     一.冒泡排序                             冒泡排序(Bubble Sort)是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为 ...

  5. Git使用详细教程(2):配置用户名和邮箱

    首先,说下最常用的设置用户名和邮箱的命令 git config --global user.name 'xxx' //设置用户名 git config --global user.email 'xxx ...

  6. 第56节:ArrayList,LinkedList和String

    import java.util.ArrayList; public class Demo{ public static void main(String[] args) throws Excepti ...

  7. C#不同窗体间数据传递

    在做项目中经常会使用不同窗体之间的值,所以就有了传值的概念.最常见的是父子窗体之间的数据传递,比如登录ID,各个窗体都需要知道. 1.       如果很多窗体都需要用到某一窗体的东西,比如登录窗体记 ...

  8. 从TXT文本文档向Sql Server中批量导入数据

    下面我们通过以下的简单的SQL语句即可实现数据的批量导入,代码如下: Bulk insert id From 'G:\文档\test.txt' With ( fieldterminator=',', ...

  9. Redis学习笔记之Redis基本数据结构

    Redis基础数据结构 Redis有5种基本数据结构:String(字符串).list(列表).set(集合).hash(哈希).zset(有序集合) 字符串string 字符串类型是Redis的va ...

  10. 将double或则float类型保留小数

    DecimalFormat df=new DecimalFormat("0.0");//“0.00” df.format(price);