三个线程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();
//        }

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

posted @ 2018-07-15 16:03  _Phoenix  阅读(16761)  评论(2编辑  收藏  举报