歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java多線程之ThreadPool

Java多線程之ThreadPool

日期:2017/3/1 10:26:15   编辑:Linux編程

這裡演示了普通線程池以及帶有返回值的線程池的使用方式

  1. package com.jadyer.thread.pool;
  2. import java.util.Random;
  3. import java.util.concurrent.Callable;
  4. import java.util.concurrent.CompletionService;
  5. import java.util.concurrent.ExecutionException;
  6. import java.util.concurrent.ExecutorCompletionService;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.Future;
  10. import java.util.concurrent.TimeUnit;
  11. /**
  12. * ThreadPool Test
  13. * @see ================================================================================================
  14. * @see 線程與進程的區別
  15. * @see 1)多個進程的內部數據和狀態是完全獨立的,而多線程則會共享一塊內存空間和一組系統資源,有可能互相影響
  16. * @see 2)線程本身的數據通常只有寄存器數據,以及一個程序執行時使用的堆棧。所以線程的切換比進程切換的負擔要小
  17. * @see ================================================================================================
  18. * @see 線程的啟動方式和消亡
  19. * @see 1)以Thread.start()啟動時,JVM會以線程的方式運行它。start()首先會為線程的執行准備系統資源,然後才去調用run方法
  20. * @see 2)以Thread.run()啟動時,JVM會以普通方法運行它。此時就不會存在線程所特有的交替執行的效果
  21. * @see 3)一個線程類的兩個對象,同時以start()方式運行時,JVM仍會把它們當作兩個線程類來執行
  22. * @see 4)終止線程時,絕對不能使用stop()方法,而應該讓run()自然結束
  23. * @see ================================================================================================
  24. * @author 宏宇
  25. * @create Feb 29, 2012 1:13:43 AM
  26. */
  27. public class ThreadPoolTest {
  28. public static void main(String[] args) {
  29. new ThreadPoolTest().threadPoolTest();
  30. new ThreadPoolTest().threadPoolScheduledTest();
  31. new ThreadPoolTest().threadPoolCallbaleAndFutureSignTest();
  32. new ThreadPoolTest().threadPoolCallbaleAndFutureMoreTest();
  33. }
  34. /**
  35. * 創建線程池的幾種方式
  36. * @see Executors.newFixedThreadPool(3); //創建固定大小的線程池
  37. * @see Executors.newCachedThreadPool(); //創建緩存線程池。它會根據實際請求的線程數量動態創建線程
  38. * @see Executors.newSingleThreadExecutor(); //創建單個線程池。它可以實現線程死掉後重新啟動的效果,但實際啟動的是"替補線程"
  39. */
  40. public void threadPoolTest(){
  41. //newSingleThreadExecutor()的好處就是,若池中的線程死了,它會把一個"替補的線程"扶上位,即它會保證池中始終有一個線程存在
  42. ExecutorService threadPool = Executors.newSingleThreadExecutor();
  43. for(int i=1; i<=10; i++) {
  44. final int task = i;
  45. threadPool.execute(new MyThread(task)); //注意execute()的返回值是void
  46. }
  47. System.out.println("all of 10 tasks have committed......");
  48. //線程池中的任務均執行完畢後,關閉線程池
  49. threadPool.shutdown();
  50. }
  51. /**
  52. * 線程池啟動定時器
  53. * @see Executors.newScheduledThreadPool(3).schedule(); //創建並執行在給定延遲後啟用的一次性操作
  54. * @see Executors.newScheduledThreadPool(3).scheduleAtFixedRate(); //首次啟動後,以固定的頻率自動執行操作
  55. * @see scheduleAtFixedRate()支持間隔重復任務的定時方式,但不直接支持絕對定時方式,我們需要轉換為相對時間的方式,來執行
  56. */
  57. public void threadPoolScheduledTest(){
  58. //10秒後自動執行一次
  59. //Executors.newScheduledThreadPool(3).schedule(new MyScheduledThread(), 10, TimeUnit.SECONDS);
  60. //6秒後首次執行,之後每2秒均自動執行一次
  61. Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new MyScheduledThread(), 6, 2, TimeUnit.SECONDS);
  62. }
  63. /**
  64. * 線程池返回一個任務的值
  65. * @see 注意:這裡需使用java.util.concurrent.ExecutorService.submit()來提交,它會返回Future對象
  66. * @see 注意:Future取得的結果類型,與Callable返回的結果類型,必須一致。我們這裡是通過泛型來實現的
  67. */
  68. public void threadPoolCallbaleAndFutureSignTest(){
  69. ExecutorService threadPool = Executors.newSingleThreadExecutor();
  70. Future<String> future = threadPool.submit(
  71. new Callable<String>() {
  72. @Override
  73. public String call() throws Exception {
  74. Thread.sleep(2000);
  75. return "張起靈";
  76. };
  77. }
  78. );
  79. System.out.println("等待結果");
  80. try {
  81. System.out.println("拿到結果:" + future.get()); //future.get(4, TimeUnit.SECONDS)
  82. } catch (InterruptedException e) {
  83. e.printStackTrace();
  84. } catch (ExecutionException e) {
  85. e.printStackTrace();
  86. }
  87. }
  88. /**
  89. * 線程池返回多個任務的值
  90. * @see java.util.concurrent.CompletionService用於提交一組Callable任務
  91. * @see CompletionService.take()會返回已完成的一個Callable任務所對應的Future對象
  92. * @see 這就好比同時種植了幾塊菜地,然後等待收菜。收菜時,哪塊菜熟了,就先去收哪塊菜地的菜
  93. */
  94. public void threadPoolCallbaleAndFutureMoreTest(){
  95. ExecutorService threadPool = Executors.newFixedThreadPool(5);
  96. CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(threadPool);
  97. for(int i=1; i<=5; i++){
  98. final int taskCode = i;
  99. completionService.submit(
  100. new Callable<Integer>(){
  101. @Override
  102. public Integer call() throws Exception {
  103. Thread.sleep(new Random().nextInt(5000));
  104. return taskCode;
  105. }
  106. }
  107. );
  108. }
  109. for(int i=0; i<5; i++){
  110. try {
  111. System.out.println(completionService.take().get());
  112. } catch (InterruptedException e) {
  113. e.printStackTrace();
  114. } catch (ExecutionException e) {
  115. e.printStackTrace();
  116. }
  117. }
  118. }
  119. }
  120. class MyThread implements Runnable{
  121. private Integer task;
  122. public MyThread(Integer task){
  123. this.task = task;
  124. }
  125. @Override
  126. public void run() {
  127. //這裡不需要寫成j,因為它和threadPoolTest()裡面的for()循環中的i並不是同一個方法中的變量,故其不會沖突
  128. for(int i=1; i<=10; i++) {
  129. try {
  130. Thread.sleep(20);
  131. } catch (InterruptedException e) {
  132. e.printStackTrace();
  133. }
  134. System.out.println(Thread.currentThread().getName() + " is looping of " + i + " for task of " + task);
  135. }
  136. }
  137. }
  138. class MyScheduledThread implements Runnable{
  139. @Override
  140. public void run() {
  141. System.out.println("bombing......");
  142. }
  143. }
Copyright © Linux教程網 All Rights Reserved