三个线程T1,T2,T3.保证顺序执行的三种方法
经常看见面试题:有三个线程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(); // }
以上就是 三个线程的顺序实现方式介绍,看了其他的博客潦草写的实现,不假思索的错误实现,希望各位自己在写东西的时候多加思考和论证!以上若有错误,欢迎评论指正