三個並發線程順序執行


如何確保三個線程順序執行

轉自:https://blog.csdn.net/Evankaka/article/details/80800081

 

場景:有三個線程t1、t2、t3。確保三個線程t1執行完后t2執行,t2執行完成后t3執行。

1.使用join

     thread.Join把指定的線程加入到當前線程,可以將兩個交替執行的線程合並為順序執行的線程。比如在線程B中調用了線程A的Join()方法,直到線程A執行完畢后,才會繼續執行線程B。

t.join();      //調用join方法,等待線程t執行完畢
t.join(1000);  //等待 t 線程,等待時間是1000毫秒。

public class ThreadTest1 {
// T1、T2、T3三個線程順序執行
public static void main(String[] args) {
    Thread t1 = new Thread(new Work(null));
    Thread t2 = new Thread(new Work(t1));
    Thread t3 = new Thread(new Work(t2));
    t1.start();
    t2.start();
    t3.start();

}
static class Work implements Runnable {
    private Thread beforeThread;
    public Work(Thread beforeThread) {
        this.beforeThread = beforeThread;
    }
    public void run() {
        if (beforeThread != null) {
            try {
                beforeThread.join();
                System.out.println("thread start:" + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            System.out.println("thread start:" + Thread.currentThread().getName());
        }
    }
}
}
2.使用CountDownLatch

     CountDownLatch(閉鎖)是一個很有用的工具類,利用它我們可以攔截一個或多個線程使其在某個條件成熟后再執行。它的內部提供了一個計數器,在構造閉鎖時必須指定計數器的初始值,且計數器的初始值必須大於0。另外它還提供了一個countDown方法來操作計數器的值,每調用一次countDown方法計數器都會減1,直到計數器的值減為0時就代表條件已成熟,所有因調用await方法而阻塞的線程都會被喚醒。這就是CountDownLatch的內部機制,看起來很簡單,無非就是阻塞一部分線程讓其在達到某個條件之后再執行。

public class ThreadTest2 {

// T1、T2、T3三個線程順序執行
public static void main(String[] args) {
    CountDownLatch c0 = new CountDownLatch(0); //計數器為0
    CountDownLatch c1 = new CountDownLatch(1); //計數器為1
    CountDownLatch c2 = new CountDownLatch(1); //計數器為1

    Thread t1 = new Thread(new Work(c0, c1));
    //c0為0,t1可以執行。t1的計數器減1

    Thread t2 = new Thread(new Work(c1, c2));
    //t1的計數器為0時,t2才能執行。t2的計數器c2減1

    Thread t3 = new Thread(new Work(c2, c2));
    //t2的計數器c2為0時,t3才能執行

    t1.start();
    t2.start();
    t3.start();

}

//定義Work線程類,需要傳入開始和結束的CountDownLatch參數
static class Work implements Runnable {
    CountDownLatch c1;
    CountDownLatch c2;

    Work(CountDownLatch c1, CountDownLatch c2) {
        super();
        this.c1 = c1;
        this.c2 = c2;
    }

    public void run() {
        try {
            c1.await();//前一線程為0才可以執行
            System.out.println("thread start:" + Thread.currentThread().getName());
            c2.countDown();//本線程計數器減少
        } catch (InterruptedException e) {
        }

    }
}
}
3.CachedThreadPool

     FutureTask一個可取消的異步計算,FutureTask 實現了Future的基本方法,提空 start cancel 操作,可以查詢計算是否已經完成,並且可以獲取計算的結果。結果只可以在計算完成之后獲取,get方法會阻塞當計算沒有完成的時候,一旦計算已經完成,那么計算就不能再次啟動或是取消。

     一個FutureTask 可以用來包裝一個 Callable 或是一個runnable對象。因為FurtureTask實現了Runnable方法,所以一個 FutureTask可以提交(submit)給一個Excutor執行(excution).

 public class ThreadTest3 {
    // T1、T2、T3三個線程順序執行
   public static void main(String[] args) {
    FutureTask<Integer> future1= new FutureTask<Integer>(new Work(null));
    Thread t1 = new Thread(future1);

    FutureTask<Integer> future2= new FutureTask<Integer>(new Work(future1));
    Thread t2 = new Thread(future2);

    FutureTask<Integer> future3= new FutureTask<Integer>(new Work(future2));
    Thread t3 = new Thread(future3);

    t1.start();
    t2.start();
    t3.start();
}

static class Work  implements Callable<Integer> {
    private FutureTask<Integer> beforeFutureTask;
    public Work(FutureTask<Integer> beforeFutureTask) {
        this.beforeFutureTask = beforeFutureTask;
    }
    public Integer call() throws Exception {
        if (beforeFutureTask != null) {
            Integer result = beforeFutureTask.get();//阻塞等待
            System.out.println("thread start:" + Thread.currentThread().getName());
        } else {
            System.out.println("thread start:" + Thread.currentThread().getName());
        }
        return 0;
    }
}
}


4.使用blockingQueue

     阻塞隊列 (BlockingQueue)是Java util.concurrent包下重要的數據結構,BlockingQueue提供了線程安全的隊列訪問方式:當阻塞隊列進行插入數據時,如果隊列已滿,線程將會阻塞等待直到隊列非滿;從阻塞隊列取數據時,如果隊列已空,線程將會阻塞等待直到隊列非空。並發包下很多高級同步類的實現都是基於BlockingQueue實現的。

public class ThreadTest4 {
// T1、T2、T3三個線程順序執行
public static void main(String[] args) {
    //blockingQueue保證順序
    BlockingQueue<Thread> blockingQueue = new LinkedBlockingQueue<Thread>();
    Thread t1 = new Thread(new Work());
    Thread t2 = new Thread(new Work());
    Thread t3 = new Thread(new Work());

    blockingQueue.add(t1);
    blockingQueue.add(t2);
    blockingQueue.add(t3);

    for (int i=0;i<3;i++) {
        Thread t = null;
        try {
            t = blockingQueue.take();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t.start();
        //檢測線程是否還活着
        while (t.isAlive());
    }
}

static class Work implements Runnable {

    public void run() {
        System.out.println("thread start:" + Thread.currentThread().getName());
    }
}
}
5.使用單個線程池

     newSingleThreadExecutor返回以個包含單線程的Executor,將多個任務交給此Exector時,這個線程處理完一個任務后接着處理下一個任務,若該線程出現異常,將會有一個新的線程來替代。

public class ThreadTest5 {

public static void main(String[] args) throws InterruptedException {
    final Thread t1 = new Thread(new Runnable() {
        public void run() {
            System.out.println(Thread.currentThread().getName() + " run 1");
        }
    }, "T1");
    final Thread t2 = new Thread(new Runnable() {
        public void run() {
            System.out.println(Thread.currentThread().getName() + " run 2");
            try {
                t1.join(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "T2");
    final Thread t3 = new Thread(new Runnable() {
        public void run() {
            System.out.println(Thread.currentThread().getName() + " run 3");
            try {
                t2.join(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }, "T3");

    //使用 單個任務的線程池來實現。保證線程的依次執行
    ExecutorService executor = Executors.newSingleThreadExecutor();
    executor.submit(t1);
    executor.submit(t2);
    executor.submit(t3);
    executor.shutdown();
}
}


免責聲明!

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



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