三個線程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();
//        }

  以上就是 三個線程的順序實現方式介紹,看了其他的博客潦草寫的實現,不假思索的錯誤實現,希望各位自己在寫東西的時候多加思考和論證!以上若有錯誤,歡迎評論指正


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM