Java多線程 5.柵欄


1.Java多線程-認識Java線程

2.Java多線程-線程安全

3.Java多線程-線程協作

4.Java多線程-線程池

5.Java多線程-柵欄

6.Java多線程-Fork/Join

 


5.1 ReadMe

  此文線程和任務可以理解為一個意思;

  Java中一般通過CountDownLantch和CyclicBarrier來解決線程(任務)之間依賴的問題,柵欄特指CyclicBarrier類,因為CountDownLatch可以實現類似功能,所以在此放到一塊講解;

  在任務A依賴任務B的這種場景可以使用Object的wait和notify來實現,但是如果任務A依賴任務B、C、D多個任務的場景,使用Object的wait和notify就難以實現,例如運動會10個人長跑(看作10個長跑任務),公布總排名這個任務就依賴至少9個長跑任務結束,這種場景適合使用CountDownLatch;

  結合實際開發過程,更多的場景是A、B、C多個任務同時執行,但是A、B、C任務在執行過程中的某一個點相互依賴,例如一個需求分為前段開發和后端開發,前后端開始聯調的時間點就是2個任務相互依賴的點,這種場景適合使用CyclicBarrier;

5.2 CountDownLatch

  Latch是門閂的意思,要打開門需要打開門上的所有門閂,CountDownLatch可以理解為一個有多個門閂的門,每個門閂需要一個的線程打開;

  代碼實現舉例:

 1 import java.security.SecureRandom;
 2 import java.util.concurrent.CountDownLatch;
 3 import java.util.concurrent.ExecutorService;
 4 import java.util.concurrent.Executors;
 5 import java.util.concurrent.TimeUnit;
 6 
 7 /**
 8  * CountDownLatch實例
 9  */
10 public class DemoCountDownLatch {
11 
12     //參賽人數 / 門閂個數
13     private static final int COUNT_RUNNER = 3;
14 
15     public static void main(String[] args) throws Exception {
16 
17         // 3人參加比賽 / 創建一個有3個門閂的門
18         CountDownLatch countDownLatch = new CountDownLatch(COUNT_RUNNER);
19 
20         // 創建3人跑道 / 裝上門
21         ExecutorService executorService = Executors.newFixedThreadPool(COUNT_RUNNER);
22 
23         for (int i = 0; i < 3; i++) {
24             executorService.submit(new Runner("runner" + i, countDownLatch));
25         }
26 
27         // 等待3人跑到終點 / 把3個門閂都鎖上
28         countDownLatch.await();
29 
30         // 公布3人成績 / 打開門了
31         System.out.println("all runner game over.");
32     }
33 
34     static class Runner implements Runnable {
35 
36         private String name;
37 
38         private CountDownLatch countDownLatch;
39 
40         public Runner(String name, CountDownLatch countDownLatch) {
41             this.name = name;
42             this.countDownLatch = countDownLatch;
43         }
44 
45         @Override
46         public void run() {
47             try {
48                 SecureRandom secureRandom = SecureRandom.getInstanceStrong();
49                 int runTime = Math.abs(secureRandom.nextInt()) % 10;
50                 TimeUnit.SECONDS.sleep(runTime);
51                 System.out.println(this.name + " game over cost " + runTime + " second.");
52             } catch (Exception e) {
53                 e.printStackTrace();
54             }
55 
56             // 跑到終點 / 打開門閂
57             this.countDownLatch.countDown();
58         }
59     }
60 }
View Code

  說明:

1. 一個CountDownLatch對象后只能使用一次,也就是說不能工作同一個CountDownLatch對象來重復控制線程的依賴問題;

2.上面的例子中如果有長跑運動員中途放棄比賽,是否永遠不能公布總的比賽成績? CountDownLatch的await可以有入參(timeout, TimeUnit)表示最長等待時間;

5.3 CyclicBarrier

 CyclicBarrier是循環柵欄的的意思,循環表示同一個CyclicBarrier可以重復使用(區別於CountDownLatch),Barrier柵欄可以理解為線程相互依賴的那個點(例如前后端聯調時間點),各個線程在那個點相互等待,等所有線程到達點后才繼續執行;

代碼實現舉例:

 1 import java.time.Instant;
 2 import java.util.concurrent.*;
 3 
 4 /**
 5  * 前端開發倩倩和后端開發厚厚開發一個需求
 6  * 兩人先獨自開發需求,等都開發完再一塊聯調功能
 7  */
 8 public class DemoCyclicBarrier
 9 {
10     public static void main(String[] args) throws InterruptedException
11     {
12 
13         // 創建柵欄,參數一為相互依賴的任務數;參數二為各任務到達依賴點后先執行的任務,等任務執行結束相互依賴的任務繼續執行
14         CyclicBarrier cyclicBarrier = new CyclicBarrier(2, () -> {
15             System.out.println("准備開始聯調吧...");
16             lastSecond(3L);
17         });
18 
19         // 創建線程池執行2個任務
20         ExecutorService executorService = Executors.newFixedThreadPool(2);
21         executorService.execute(new Coder(10L, "后端", cyclicBarrier));
22         executorService.execute(new Coder(3L, "前端", cyclicBarrier));
23     }
24 
25     /**
26      * 線程持續second秒
27      */
28     private static void lastSecond(long second)
29     {
30         Instant instant = Instant.now();
31         while (Instant.now().minusSeconds(second).isBefore(instant))
32         {
33         }
34     }
35 
36     static class Coder implements Runnable
37     {
38         // 完成工作需要的時間
39         private long workTime;
40 
41         private String name;
42 
43         private CyclicBarrier cyclicBarrier;
44 
45         public Coder(long workTime, String name, CyclicBarrier cyclicBarrier)
46         {
47             this.workTime = workTime;
48             this.name = name;
49             this.cyclicBarrier = cyclicBarrier;
50         }
51 
52         @Override
53         public void run()
54         {
55             try
56             {
57                 System.out.println(this.name + " are coding...");
58                 lastSecond(this.workTime);
59                 System.out.println(this.name + " code end wait debugging..");
60                 // 完成工作/到達依賴的點/我這邊可以開始聯調了
61                 this.cyclicBarrier.await();
62                 System.out.println("we are debugging..");
63 
64             }
65             catch (InterruptedException e)
66             {
67                 // 當前線程被中斷
68                 e.printStackTrace();
69             }
70             catch (BrokenBarrierException e)
71             {
72                 // 1.其他線程中斷;2.其他線程await方法超時;3.cyclicBarrier重置
73                 e.printStackTrace();
74             }
75             // catch (TimeoutException e)
76             // {
77             // //當前線程的await方法超時(await方法設置超時參數)
78             // e.printStackTrace();
79             // }
80         }
81     }
82 }
View Code

說明:

1.CyclicBarrier作為循環柵欄,同一個對象可以循環使用;

2.上面例子中前端開發人員很短時間開發結束,通過await()一直在等待后端開發結束,可以通過await(timeout, TimeUnit)來設置最長等待時間;

3. 可以通過CyclicBarrier的getNumberWaiting()查看到達依賴點的任務;

4.CyclicBarrier構造方法的第二個參數指定的任務A,在其他相互依賴的任務到達依賴點后,任務A優先執行,並且是執行結束,其他任務才繼續執行;

5.4 CyclicBarrier&CountDownLatch舉例

 1 import java.time.Instant;
 2 import java.util.concurrent.*;
 3 
 4 public class Demo_CyclicBarrier_CountDownLatch
 5 {
 6     private static final int COUNT_WORKER = 2;
 7 
 8     public static void main(String[] args) throws InterruptedException
 9     {
10         CountDownLatch countDownLatch = new CountDownLatch(COUNT_WORKER);
11         CyclicBarrier cyclicBarrier = new CyclicBarrier(COUNT_WORKER, () -> {
12             System.out.println("准備開始聯調吧...");
13             lastSecond(3L);
14         });
15 
16         ExecutorService executorService = Executors.newFixedThreadPool(2);
17         executorService.execute(new Coder(10L, "后端", countDownLatch, cyclicBarrier));
18         executorService.execute(new Coder(3L, "前端", countDownLatch, cyclicBarrier));
19 
20         countDownLatch.await();
21         System.out.println("開發聯調結束,需求交付...");
22     }
23 
24     /**
25      * 線程持續second秒
26      */
27     private static void lastSecond(long second)
28     {
29         Instant instant = Instant.now();
30         while (Instant.now().minusSeconds(second).isBefore(instant))
31         {
32         }
33     }
34 
35     static class Coder implements Runnable
36     {
37         // 開發聯調時間
38         private long workTime;
39 
40         private String name;
41 
42         private CountDownLatch countDownLatch;
43 
44         private CyclicBarrier cyclicBarrier;
45 
46         public Coder(long workTime, String name, CountDownLatch countDownLatch, CyclicBarrier cyclicBarrier)
47         {
48             this.workTime = workTime;
49             this.name = name;
50             this.countDownLatch = countDownLatch;
51             this.cyclicBarrier = cyclicBarrier;
52         }
53 
54         @Override
55         public void run()
56         {
57             try
58             {
59                 System.out.println(this.name + " are coding...");
60                 lastSecond(this.workTime);
61                 System.out.println(this.name + " code end wait debugging..");
62 
63                 this.cyclicBarrier.await();
64 
65                 System.out.println(this.name + " are debugging..");
66                 lastSecond(this.workTime);
67 
68                 System.out.println(this.name + " debug end..");
69                 this.countDownLatch.countDown();
70             }
71             catch (Exception e)
72             {
73                 e.printStackTrace();
74             }
75         }
76     }
77 }
View Code


免責聲明!

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



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