激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java多線程下的其他組件之CyclicBarrier、Callable、Future和FutureTask詳解

Java多線程下的其他組件之CyclicBarrier、Callable、Future和FutureTask詳解

2020-08-01 00:25五月的倉頡 Java教程

這篇文章主要介紹了Java多線程下的其他組件之CyclicBarrier、Callable、Future和FutureTask詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

CyclicBarrier

       接著講多線程下的其他組件,第一個要講的就是CyclicBarrier。CyclicBarrier從字面理解是指循環屏障,它可以協同多個線程,讓多個線程在這個屏障前等待,直到所有線程都達到了這個屏障時,再一起繼續執行后面的動作。看一下CyclicBarrier的使用實例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public static class CyclicBarrierThread extends Thread
{
  private CyclicBarrier cb;
  private int sleepSecond;
    
  public CyclicBarrierThread(CyclicBarrier cb, int sleepSecond)
  {
    this.cb = cb;
    this.sleepSecond = sleepSecond;
  }
    
  public void run()
  {
    try
    {
      System.out.println(this.getName() + "運行了");
      Thread.sleep(sleepSecond * 1000);
      System.out.println(this.getName() + "準備等待了, 時間為" + System.currentTimeMillis());
      cb.await();
      System.out.println(this.getName() + "結束等待了, 時間為" + System.currentTimeMillis());
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}
  
public static void main(String[] args)
{
  Runnable runnable = new Runnable()
  {
    public void run()
    {
      System.out.println("CyclicBarrier的所有線程await()結束了,我運行了, 時間為" + System.currentTimeMillis());
    }
  };
  CyclicBarrier cb = new CyclicBarrier(3, runnable);
  CyclicBarrierThread cbt0 = new CyclicBarrierThread(cb, 3);
  CyclicBarrierThread cbt1 = new CyclicBarrierThread(cb, 6);
  CyclicBarrierThread cbt2 = new CyclicBarrierThread(cb, 9);
  cbt0.start();
  cbt1.start();
  cbt2.start();
}

看一下運行結果:

Thread-0運行了
Thread-2運行了
Thread-1運行了
Thread-0準備等待了, 時間為1444650316313
Thread-1準備等待了, 時間為1444650319313
Thread-2準備等待了, 時間為1444650322313
CyclicBarrier的所有線程await()結束了,我運行了, 時間為1444650322313
Thread-2結束等待了, 時間為1444650322313
Thread-0結束等待了, 時間為1444650322313
Thread-1結束等待了, 時間為1444650322313

從運行結果看,由于是同一個CyclicBarrier,Thread-0先運行到了await()的地方,等著;Thread-2接著運行到了await()的地方,還等著;Thread-1最后運行到了await()的地方,所有的線程都運行到了await()的地方,所以三個線程以及指定的Runnable"同時"運行后面的代碼,可以看到,await()之后,四個線程運行的時間一模一樣,都是1444650322313。

從使用來看,可能有人覺得CyclicBarrier和CountDownLatch有點像,都是多個線程等待相互完成之后,再執行后面的代碼。實際上,CountDownLatch和CyclicBarrier都是用于多個線程間的協調的,它們二者的幾個差別是:

1、CountDownLatch是在多個線程都進行了latch.countDown()后才會觸發事件,喚醒await()在latch上的線程,而執行countDown()的線程,執行完countDown()后會繼續自己線程的工作;CyclicBarrier是一個柵欄,用于同步所有調用await()方法的線程,線程執行了await()方法之后并不會執行之后的代碼,而只有當執行await()方法的線程數等于指定的parties之后,這些執行了await()方法的線程才會同時運行

2、CountDownLatch不能循環使用,計數器減為0就減為0了,不能被重置;CyclicBarrier提供了reset()方法,支持循環使用

3、CountDownLatch當調用countDown()方法的線程數等于指定的數量之后,可以喚起多條線程的任務;CyclicBarrier當執行await()方法的線程等于指定的數量之后,只能喚起一個BarrierAction

注意,因為使用CyclicBarrier的線程都會阻塞在await方法上,所以在線程池中使用CyclicBarrier時要特別小心,如果線程池的線程過少,那么就會發生死鎖了

CallableFutureFutureTask

Callable

Callable和Runnable差不多,兩者都是為那些其實例可能被另一個線程執行的類而設計的,最主要的差別在于Runnable不會返回線程運算結果,Callable可以(假如線程需要返回運行結果)

Future

Future是一個接口表示異步計算的結果,它提供了檢查計算是否完成的方法,以等待計算的完成,并獲取計算的結果。Future提供了get()、cancel()、isCancel()、isDone()四種方法,表示Future有三種功能:

1、判斷任務是否完成

2、中斷任務

3、獲取任務執行結果

FutureTask

FutureTask是Future的實現類,它提供了對Future的基本實現。可使用FutureTask包裝Callable或Runnable對象,因為FutureTask實現了Runnable,所以也可以將FutureTask提交給Executor。

使用方法

Callable、Future、FutureTask一般都是和線程池配合使用的,因為線程池ThreadPoolExecutor的父類AbstractExecutorService提供了三種submit方法:

1、public Future<?> subit(Runnable task){...}

2、public <T> Future<T> submit<Runnable task, T result>{...}

3、public <T> Future<T> submit<Callable<T> task>{...}

第2個用得不多,第1個和第3個比較有用

Callable+Future使用示例

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static class CallableThread implements Callable<String>
{
  public String call() throws Exception
  {
    System.out.println("進入CallableThread的call()方法, 開始睡覺, 睡覺時間為" + System.currentTimeMillis());
    Thread.sleep(10000);
    return "123";
  }
}
  
public static void main(String[] args) throws Exception
{
  ExecutorService es = Executors.newCachedThreadPool();
  CallableThread ct = new CallableThread();
  Future<String> f = es.submit(ct);
  es.shutdown();
    
  Thread.sleep(5000);
  System.out.println("主線程等待5秒, 當前時間為" + System.currentTimeMillis());
    
  String str = f.get();
  System.out.println("Future已拿到數據, str = " + str + ", 當前時間為" + System.currentTimeMillis());
}

運行結果為:

進入CallableThread的call()方法, 開始睡覺, 睡覺時間為1444654421368
主線程等待5秒, 當前時間為1444654426369
Future已拿到數據, str = 123, 當前時間為1444654431369

看到任意一個利用Callable接口submit上去的任務,只要有一個Future接受它,Future便可以在程序任何地點嘗試去獲取這條線程返回出去的數據,時間可以比對一下,正好10000ms,即10s

Callable+FutureTask使用示例

有興趣的可以看下源碼,其實使用Callable+Future的方式,es.submit(ct)方法返回的Future,底層實現new出來的是一個FutureTask。那么,我們看一下Callable+FutureTask的方式:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static class CallableThread implements Callable<String>
{
  public String call() throws Exception
  {
    System.out.println("進入CallableThread的call()方法, 開始睡覺, 睡覺時間為" + System.currentTimeMillis());
    Thread.sleep(10000);
    return "123";
  }
}
  
public static void main(String[] args) throws Exception
{
  ExecutorService es = Executors.newCachedThreadPool();
  CallableThread ct = new CallableThread();
  FutureTask<String> f = new FutureTask<String>(ct);
  es.submit(f);
  es.shutdown();
    
  Thread.sleep(5000);
  System.out.println("主線程等待5秒, 當前時間為" + System.currentTimeMillis());
    
  String str = f.get();
  System.out.println("Future已拿到數據, str = " + str + ", 當前時間為" + System.currentTimeMillis());
}

看下運行結果:

進入CallableThread的call()方法, 開始睡覺, 睡覺時間為1444655049199
主線程等待5秒, 當前時間為1444655054200
Future已拿到數據, str = 123, 當前時間為1444655059200

和上面的寫法運行結果一樣,就不解釋了

使用Callable、Future和FutureTask的好處

上面演示了兩個例子,其實反映的是現實中一種情況,把上面的例子稍微擴展一下就是:

有一個method()方法,方法中執行方法A返回一個數據要10秒鐘,A方法后面的代碼一共要執行20秒鐘,但是這20秒的代碼中有10秒的方法并不依賴方法A的執行結果,有10秒鐘的代碼依賴方法A的執行結果。此時若采用同步的方式,那么勢必要先等待10秒鐘,等待方法A執行完畢,返回數據,再執行后面20秒的代碼。

不得不說這是一種低效率的做法。有了Callable、Future和FutureTask,那么:

1、先把A方法的內容放到Callable實現類的call()方法中

2、method()方法中,Callable實現類傳入Executor的submit方法中

3、執行后面方法中10秒不依賴方法A運行結果的代碼

4、獲取方法A的運行結果,執行后面方法中10秒依賴方法A運行結果的代碼

這樣代碼執行效率一下子就提高了,程序不必卡在A方法處。

當然,也可以不用Callable,采用實現Runnable的方式,run()方法執行完了想個辦法給method()方法中的某個變量V賦個值就好了。但是我上一篇文章開頭就說了,之所以要用多線程組件,就是因為JDK幫我們很好地實現好了代碼細節,讓開發者更多可以關注業務層的邏輯。如果使用Runnable的方式,那么我們自己就要考慮很多細節,比如Runnable實現類的run()方法執行完畢給V賦值是否線程安全、10秒后如果A方法沒有執行完導致V還沒有值怎么辦,何況JDK還給用戶提供了取消任務、判斷任務是否存在等方法。既然JDK已經幫我們考慮并實現這些細節了,在沒有有說服力的理由的情況下,我們為什么還要自己寫run()方法的實現呢?

到此這篇關于Java多線程下的其他組件之CyclicBarrier、Callable、Future和FutureTask詳解的文章就介紹到這了,更多相關Java多線程下的其他組件內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/xrq730/p/4872722.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 奇米影视888狠狠狠777不卡 | 嗯~啊~弄嗯~啊h高潮视频 | 中国美女一级黄色大片 | xnxx 日本19 | 婷婷一区二区三区 | av免费在线观看av | 亚洲一区二区成人 | 欧美特级一级毛片 | 精品一区二区在线播放 | 久久精品亚洲成在人线av网址 | 成人免费久久 | 成年人免费视频播放 | 亚洲成人福利在线 | 久久一本日日摸夜夜添 | 久久一区国产 | 国产拍拍拍三级费视频在线观看 | 色诱亚洲精品久久久久久 | 日本a v免费观看 | 亚洲网站在线 | 91在线视频网址 | 国产一区二区二 | 性欧美极品xxxx欧美一区二区 | 夜夜看 | 一区二区三区四区高清视频 | av免播放| 免费看国产视频 | 欧美成人激情 | 久久国产秒 | 精品欧美一区二区精品久久 | 91九色视频在线播放 | 亚洲成人欧美在线 | 日韩激情 | 99久久精品免费看国产小宝寻花 | 欧美一级三级在线观看 | 毛片网站网址 | 日本免费中文字幕 | 日本aaaa片毛片免费观蜜桃 | 黄色片网站在线免费观看 | 国产电影av在线 | 天天色人人爱 | 黄色免费电影网址 |