欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 使用線程池執(zhí)行多個任務的示例

 更新時間:2021年03月03日 10:59:47   作者:robothy  
這篇文章主要介紹了Java 使用線程池執(zhí)行多個任務的示例,幫助大家更好的理解和學習使用Java,感興趣的朋友可以了解下

在執(zhí)行一系列帶有IO操作(例如下載文件),且互不相關的異步任務時,采用多線程可以很極大的提高運行效率。線程池包含了一系列的線程,并且可以管理這些線程。例如:創(chuàng)建線程,銷毀線程等。本文將介紹如何使用Java中的線程池執(zhí)行任務。

1 任務類型

在使用線程池執(zhí)行任務之前,我們弄清楚什么任務可以被線程池調用。按照任務是否有返回值可以將任務分為兩種,分別是實現(xiàn)Runnable的任務類(無參數(shù)無返回值)和實現(xiàn)Callable接口的任務類(無參數(shù)有返回值)。在打代碼時根據(jù)需求選擇對應的任務類型。

1.1 實現(xiàn)Runnable接口的類

多線程任務類型,首先自然想到的就是實現(xiàn) Runnable 接口的類,Runnable接口提供了一個抽象方法run,這個方法無參數(shù),無返回值。例如:

Runnable task = new Runnable() {
  @Override
  public void run() {
    System.out.println("Execute task.");
  }
};

或者Java 8 及以上版本更簡單的寫法:

Runnable task = ()->{
  System.out.println("Execute task.");
};

1.2 實現(xiàn)Callable接口的類

于Runnable一樣Callable也只有一個抽象方法,不過該抽象方法有返回值。在實現(xiàn)該接口的時候需要制定返回值的類型。例如:

Callable<String> callableTask = ()-> "finished";

2 線程池類型

java.util.concurrent.Executors 提供了一系列靜態(tài)方法來創(chuàng)建各種線程池。下面例舉出了主要的一些線程池及特性,其它未例舉線程池的特性可由下面這些推導出來。

2.1 線程數(shù)固定的線程池 Fixed Thread Pool

顧名思義,這種類型線程池線程數(shù)量是固定的。如果線程數(shù)量設置為n,則任何時刻該線程池最多只有n個線程處于運行狀態(tài)。當線程池中處于飽和運行狀態(tài)時,再往線程池中提交的任務會被放到執(zhí)行隊列中。如果線程池處于不飽和狀態(tài),線程池也會一直存在,直到ExecuteService 的shutdown方法被調用,線程池才會被清除。

// 創(chuàng)建線程數(shù)量為5的線程池。
ExecutorService executorService = Executors.newFixedThreadPool(5);

2.2 可緩存的線程池 Cached Thread Pool

這種類型的線程池初始大小為0個線程,隨著往池里不斷提交任務,如果線程池里面沒有閑置線程(0個線程也表示沒有閑置線程),則會創(chuàng)建新的線程,保證沒有任務在等待;如果有閑置線程,則復用閑置狀態(tài)線程執(zhí)行任務。處于閑置狀態(tài)的線程只會在線程池中緩存60秒,閑置時間達到60s的線程會被關閉并移出線程池。在處理大量短暫的(官方說法:short-lived)異步任務時可以顯著得提供程序性能。

//創(chuàng)建一個可緩存的線程池 
ExecutorService executorService = Executors.newCachedThreadPool();

2.3 單線程池

這或許不能叫線程池了,由于它里面的線程永遠只有1個,而且自始至終都只有1個(為什么說這句話,因為要和 Executors.newFixedThreadPool(1) 區(qū)別開來),所以還是叫它“單線程池把”。你盡可以往單線程池中添加任務,但是每次只執(zhí)行1個,且任務是按順序執(zhí)行的。如果前面的任務出現(xiàn)了異常,當前線程會被銷毀,但1個新的線程會被創(chuàng)建用來執(zhí)行后面的任務。以上這些和線程數(shù)只有1個的線程Fixed Thread Pool一樣。兩者唯一不同的是, Executors.newFixedThreadPool(1) 可以在運行時修改它里面的線程數(shù),而 Executors.newSingleThreadExecutor() 永遠只能有1個線程。

//創(chuàng)建一個單線程池
ExecutorService executorService = Executors.newSingleThreadExecutor();

2.4 工作竊取線程池

扒開源碼,會發(fā)現(xiàn)工作竊取線程池本質是 ForkJoinPool ,這類線程池充分利用CPU多核處理任務,適合處理消耗CPU資源多的任務。它的線程數(shù)不固定,維護的任務隊列有多個,當一個任務隊列完成時,相應的線程會從其它的任務隊列中竊取任務執(zhí)行,這也意味著任務的開始執(zhí)行順序并和提交順序相同。如果有更高的需求,可以直接通過ForkJoinPool獲取線程池。

//創(chuàng)建一個工作竊取線程池,使用CPU核數(shù)等于機器的CPU核數(shù)
ExecutorService executorService = Executors.newWorkStealingPool();

//創(chuàng)建一個工作竊取線程池,使用CPU 3 個核進行計算,工作竊取線程池不能設置線程數(shù)
ExecutorService executorService2 = Executors.newWorkStealingPool(3);

2.5 計劃任務線程池

計劃任務線程池可以按計劃執(zhí)行某些任務,例如:周期性的執(zhí)行某項任務。

// 獲取一個大小為2的計劃任務線程池
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2);
// 添加一個打印當前線程信息計劃任務,該任務在3秒后執(zhí)行
scheduledExecutorService.schedule(() -> { System.out.println(Thread.currentThread()); }, 3, TimeUnit.SECONDS);
// 添加一個打印當前線程信息計劃任務,該任務在2秒后首次執(zhí)行,之后每5秒執(zhí)行一次。如果任務執(zhí)行時間超過了5秒,則下一次將會在前一次執(zhí)行完成之后立即執(zhí)行
scheduledExecutorService.scheduleAtFixedRate(() -> { System.out.println(Thread.currentThread()); }, 2, 5, TimeUnit.SECONDS);
// 添加一個打印當前線程信息計劃任務,該任務在2秒后首次執(zhí)行,之后每次在任務執(zhí)行之后5秒執(zhí)行下一次。
scheduledExecutorService.scheduleWithFixedDelay(() -> { System.out.println(Thread.currentThread()); }, 2, 5, TimeUnit.SECONDS);
// 逐個清除 idle 狀態(tài)的線程
scheduledExecutorService.shutdown();
// 阻塞,在線程池被關調之前代碼不再往下走
scheduledExecutorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

3 使用線程池執(zhí)行任務

前面提到,任務類型分為有返回值和無返回值的類型,這里的調用也分為有返回值調用和無返回值的調用。

3.1 無返回值任務的調用

如果是無返回值任務的調用,可以用execute或者submit方法,這種情況下二者本質上一樣。為了于有返回值任務調用保持統(tǒng)一,建議采用submit方法。

//創(chuàng)建一個線程池
ExecutorService executorService = Executors.newFixedThreadPool(3);

//提交一個無返回值的任務(實現(xiàn)了Runnable接口)
executorService.submit(()->System.out.println("Hello"));

executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

如果有一個任務集合,可以一個個提交。

//創(chuàng)建一個線程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Runnable> tasks = Arrays.asList(
    ()->System.out.println("Hello"),
    ()->System.out.println("World"));

//逐個提交任務
tasks.forEach(executorService::submit);

executorService.shutdown();
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);

3.2 有返回值任務的調用

有返回值的任務需要實現(xiàn)Callable接口,實現(xiàn)的時候在泛型位置指定返回值類型。在調用submit方法時會返回一個Future對象,通過Future的方法get()可以拿到返回值。這里需要注意的是,調用get()時代碼會阻塞,直到任務完成,有返回值。

ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<String> future = executorService.submit(()->"Hello");
System.out.println(future.isDone());//false
String value = future.get();
System.out.println(future.isDone());//true
System.out.println(value);//Hello

如果要提交一批任務,ExecutorService除了可以逐個提交之外,還可以調用invokeAll一次性提交,invokeAll的內部實現(xiàn)其實就是用一個循環(huán)逐個提交任務。invokeAll返回的值是一個Future List。

ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Callable<String>> tasks = Arrays.asList(()->"Hello", ()->"World");
List<Future<String>> futures = executorService.invokeAll(tasks);

invokeAny方法也很有用,線程池執(zhí)行若干個實現(xiàn)了Callable的任務,然后返回最先執(zhí)行結束的任務的值,其它未完成的任務將被正常取消掉不會有異常。如下代碼不會輸出“Hello”

ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Callable<String>> tasks = Arrays.asList(
    () -> {
      Thread.sleep(500L);
      System.out.println("Hello");
      return "Hello";
    }, () -> {
      System.out.println("World");
      return "World";
    });
String s = executorService.invokeAny(tasks);
System.out.println(s);//World

輸出:

World
World

另外,在查看ExecutorService源碼時發(fā)現(xiàn)它還提供了一個方法 <T> Future<T> submit(Runnable task, T result); ,可以通過這個方法提交一個實現(xiàn)了Runnable接口的任務,然后有返回值,而Runnable接口中的run方法時沒有返回值的。那它的返回值是哪來的呢?其實問題在于該submit方法后面的一個參數(shù),這個參數(shù)值就是返回的值。調用submit方法之后,有一通操作,然后直接把result參數(shù)返回了。

ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<String> future = executorService.submit(() -> System.out.println("Hello"), "World");
System.out.println(future.get());//輸出:World

4 小結

在利用多線程處理任務時,應該根據(jù)情況選擇合適的任務類型和線程池類型。如果無返回值,可以采用實現(xiàn)Runnable或Callable接口的任務;如果有返回值,應該使用實現(xiàn)Callable接口的任務,返回值通過Future的get方法取到。選用線程池時,如果只用1個線程,用單線程池或者容量為1的固定容量線程池;處理大量short-live任務是,使用可緩存的線程池;若要有計劃或者循環(huán)執(zhí)行某些任務,可以采用計劃任務線程池;如果任務需要消耗大量的CPU資源,應用工作竊取線程池。

以上就是Java 使用線程池執(zhí)行多個任務的示例的詳細內容,更多關于Java 線程池執(zhí)行任務的資料請關注腳本之家其它相關文章!

相關文章

  • HashMap和Hashtable的詳細比較

    HashMap和Hashtable的詳細比較

    這篇文章主要介紹了HashMap和Hashtable的詳細比較的相關資料,需要的朋友可以參考下
    2017-04-04
  • 不同方式遍歷Map集合(全)

    不同方式遍歷Map集合(全)

    大家都知道Map是一種以鍵值對的形式存在的集合,其中每個鍵映射到一個值,下面把Map遍歷集合總結了一下給大家分享下,需要的朋友可以參考下
    2015-07-07
  • java枚舉類的屬性、方法和構造方法應用實戰(zhàn)

    java枚舉類的屬性、方法和構造方法應用實戰(zhàn)

    這篇文章主要介紹了java枚舉類的屬性、方法和構造方法應用,結合實例形式分析了java枚舉類的定義、構造及相關應用操作技巧,需要的朋友可以參考下
    2019-08-08
  • SpringBoot配置Spring?Security的實現(xiàn)示例

    SpringBoot配置Spring?Security的實現(xiàn)示例

    本文主要介紹了SpringBoot配置Spring?Security的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2024-10-10
  • 如何使用Spring工具類動態(tài)匹配url

    如何使用Spring工具類動態(tài)匹配url

    這篇文章主要介紹了如何使用Spring工具類動態(tài)匹配url,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-12-12
  • 簡單捋捋@RequestParam 和 @RequestBody的使用

    簡單捋捋@RequestParam 和 @RequestBody的使用

    這篇文章主要介紹了簡單捋捋@RequestParam 和 @RequestBody的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-12-12
  • Java中的LinkedHashSet和TreeSet解讀

    Java中的LinkedHashSet和TreeSet解讀

    這篇文章主要介紹了Java中的LinkedHashSet和TreeSet解讀,哈希表和鏈表實現(xiàn)的set接口哈希表決定了它元素是唯一的,而鏈表則保證了他是有序的(存儲和取出順序一致),元素按照一定規(guī)則排序,不是按儲存時間排的,需要的朋友可以參考下
    2023-09-09
  • mybatis 解決從列名到屬性名的自動映射失敗問題

    mybatis 解決從列名到屬性名的自動映射失敗問題

    這篇文章主要介紹了mybatis 解決從列名到屬性名的自動映射失敗問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • SpringBoot2底層注解@ConfigurationProperties配置綁定

    SpringBoot2底層注解@ConfigurationProperties配置綁定

    這篇文章主要介紹了SpringBoot2底層注解@ConfigurationProperties配置綁定,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • Java GUI編程之貪吃蛇游戲簡單實現(xiàn)方法【附demo源碼下載】

    Java GUI編程之貪吃蛇游戲簡單實現(xiàn)方法【附demo源碼下載】

    這篇文章主要介紹了Java GUI編程之貪吃蛇游戲簡單實現(xiàn)方法,詳細分析了貪吃蛇游戲的具體實現(xiàn)步驟與相關注意事項,并附帶demo源碼供讀者下載參考,需要的朋友可以參考下
    2017-09-09

最新評論