经常看见面试题:有三个线程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();
// }

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

最新文章

  1. 窥探Swift编程之在Playground上尽情的玩耍
  2. iOS 两行代码解决数据持久化
  3. C#调用C++编写的DLL函数, 以及各种类型的参数传递 (转载)
  4. 洛谷P2633 王后万岁
  5. js笔记——浏览器及版本判断
  6. Redhat 6 配置CentOS yum source
  7. Android主题换肤 无缝切换
  8. 2016iweb峰会参会总结
  9. mysql笔记之主从切换
  10. SCJP_104——题目分析(3)
  11. [Leetcode][020] Valid Parentheses (Java)
  12. HTML5扩展之微数据与丰富网页摘要itemscope, itemtype, itemprop
  13. javascript 学习笔记 三大特性
  14. kafka基本介绍
  15. Linux基础 - 系统优化及常用命令
  16. 在IE浏览器进行编辑操作再展示出现乱码问题
  17. EJB到底是什么
  18. Newtonsoft.Json 序列化小写首字母
  19. ASP.NET MVC开发,编辑页面和添加页面基本相同,我们控制器 Add Edit是共用同一个View吗?
  20. [ExtJs] ExtJs4.2 数据模型Ext.data.Model学习

热门文章

  1. Java编程题(1):n个数里出现次数大于等于n/2的数
  2. Linux pwn入门教程(10)——针对函数重定位流程的几种攻击
  3. C/C++中宏定义#pragma once与 #ifndef的区别
  4. 基于nodemailer使用阿里云企业邮箱发送邮件(526错误的解决)
  5. 转载----开发者大杀器 —— 刨根问底,揪出 Android App 耗电的元凶代码
  6. Oracle SQL调优记录
  7. HBuilder+eclipse开发:使用ajax异步传值生成首字母索引
  8. parseInt和map方法使用案例分析
  9. Redis(2)---数据持久化
  10. centos7通过yum安装nginx