歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Java多線程總結五:線程池的原理及實現

Java多線程總結五:線程池的原理及實現

日期:2017/3/1 10:55:59   编辑:Linux編程

1、線程池簡介:
多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閒置時間,增加處理器單元的吞吐能力。
假設一個服務器完成一項任務所需時間為:T1 創建線程時間,T2 在線程中執行任務的時間,T3 銷毀線程時間。

如果:T1 + T3 遠大於 T2,則可以采用線程池,以提高服務器性能。
一個線程池包括以下四個基本組成部分:
1、線程池管理器(ThreadPool):用於創建並管理線程池,包括 創建線程池,銷毀線程池,添加新任務;
2、工作線程(PoolWorker):線程池中線程,在沒有任務時處於等待狀態,可以循環的執行任務;
3、任務接口(Task):每個任務必須實現的接口,以供工作線程調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工作,任務的執行狀態等;
4、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩沖機制。

線程池技術正是關注如何縮短或調整T1,T3時間的技術,從而提高服務器程序性能的。它把T1,T3分別安排在服務器程序的啟動和結束的時間段或者一些空閒的時間段,這樣在服務器程序處理客戶請求時,不會有T1,T3的開銷了。
線程池不僅調整T1,T3產生的時間段,而且它還顯著減少了創建線程的數目,看一個例子:
假設一個服務器一天要處理50000個請求,並且每個請求需要一個單獨的線程完成。在線程池中,線程數一般是固定的,所以產生線程總數不會超過線程池中線程的數目,而如果服務器不利用線程池來處理這些請求則線程總數為50000。一般線程池大小是遠小於50000。所以利用線程池的服務器程序不會為了創建50000而在處理請求時浪費時間,從而提高效率。

代碼實現中並沒有實現任務接口,而是把Runnable對象加入到線程池管理器(ThreadPool),然後剩下的事情就由線程池管理器(ThreadPool)來完成了

  1. package mine.util.thread;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. /**
  5. * 線程池類,線程管理器:創建線程,執行任務,銷毀線程,獲取線程基本信息
  6. */
  7. public final class ThreadPool {
  8. // 線程池中默認線程的個數為5
  9. private static int worker_num = 5;
  10. // 工作線程
  11. private WorkThread[] workThrads;
  12. // 未處理的任務
  13. private static volatile int finished_task = 0;
  14. // 任務隊列,作為一個緩沖,List線程不安全
  15. private List<Runnable> taskQueue = new LinkedList<Runnable>();
  16. private static ThreadPool threadPool;
  17. // 創建具有默認線程個數的線程池
  18. private ThreadPool() {
  19. this(5);
  20. }
  21. // 創建線程池,worker_num為線程池中工作線程的個數
  22. private ThreadPool(int worker_num) {
  23. ThreadPool.worker_num = worker_num;
  24. workThrads = new WorkThread[worker_num];
  25. for (int i = 0; i < worker_num; i++) {
  26. workThrads[i] = new WorkThread();
  27. workThrads[i].start();// 開啟線程池中的線程
  28. }
  29. }
  30. // 單態模式,獲得一個默認線程個數的線程池
  31. public static ThreadPool getThreadPool() {
  32. return getThreadPool(ThreadPool.worker_num);
  33. }
  34. // 單態模式,獲得一個指定線程個數的線程池,worker_num(>0)為線程池中工作線程的個數
  35. // worker_num<=0創建默認的工作線程個數
  36. public static ThreadPool getThreadPool(int worker_num1) {
  37. if (worker_num1 <= 0)
  38. worker_num1 = ThreadPool.worker_num;
  39. if (threadPool == null)
  40. threadPool = new ThreadPool(worker_num1);
  41. return threadPool;
  42. }
  43. // 執行任務,其實只是把任務加入任務隊列,什麼時候執行有線程池管理器覺定
  44. public void execute(Runnable task) {
  45. synchronized (taskQueue) {
  46. taskQueue.add(task);
  47. taskQueue.notify();
  48. }
  49. }
  50. // 批量執行任務,其實只是把任務加入任務隊列,什麼時候執行有線程池管理器覺定
  51. public void execute(Runnable[] task) {
  52. synchronized (taskQueue) {
  53. for (Runnable t : task)
  54. taskQueue.add(t);
  55. taskQueue.notify();
  56. }
  57. }
  58. // 批量執行任務,其實只是把任務加入任務隊列,什麼時候執行有線程池管理器覺定
  59. public void execute(List<Runnable> task) {
  60. synchronized (taskQueue) {
  61. for (Runnable t : task)
  62. taskQueue.add(t);
  63. taskQueue.notify();
  64. }
  65. }
  66. // 銷毀線程池,該方法保證在所有任務都完成的情況下才銷毀所有線程,否則等待任務完成才銷毀
  67. public void destroy() {
  68. while (!taskQueue.isEmpty()) {// 如果還有任務沒執行完成,就先睡會吧
  69. try {
  70. Thread.sleep(10);
  71. } catch (InterruptedException e) {
  72. e.printStackTrace();
  73. }
  74. }
  75. // 工作線程停止工作,且置為null
  76. for (int i = 0; i < worker_num; i++) {
  77. workThrads[i].stopWorker();
  78. workThrads[i] = null;
  79. }
  80. threadPool=null;
  81. taskQueue.clear();// 清空任務隊列
  82. }
  83. // 返回工作線程的個數
  84. public int getWorkThreadNumber() {
  85. return worker_num;
  86. }
  87. // 返回已完成任務的個數,這裡的已完成是只出了任務隊列的任務個數,可能該任務並沒有實際執行完成
  88. public int getFinishedTasknumber() {
  89. return finished_task;
  90. }
  91. // 返回任務隊列的長度,即還沒處理的任務個數
  92. public int getWaitTasknumber() {
  93. return taskQueue.size();
  94. }
  95. // 覆蓋toString方法,返回線程池信息:工作線程個數和已完成任務個數
  96. @Override
  97. public String toString() {
  98. return "WorkThread number:" + worker_num + " finished task number:"
  99. + finished_task + " wait task number:" + getWaitTasknumber();
  100. }
  101. /**
  102. * 內部類,工作線程
  103. */
  104. private class WorkThread extends Thread {
  105. // 該工作線程是否有效,用於結束該工作線程
  106. private boolean isRunning = true;
  107. /*
  108. * 關鍵所在啊,如果任務隊列不空,則取出任務執行,若任務隊列空,則等待
  109. */
  110. @Override
  111. public void run() {
  112. Runnable r = null;
  113. while (isRunning) {// 注意,若線程無效則自然結束run方法,該線程就沒用了
  114. synchronized (taskQueue) {
  115. while (isRunning && taskQueue.isEmpty()) {// 隊列為空
  116. try {
  117. taskQueue.wait(20);
  118. } catch (InterruptedException e) {
  119. e.printStackTrace();
  120. }
  121. }
  122. if (!taskQueue.isEmpty())
  123. r = taskQueue.remove(0);// 取出任務
  124. }
  125. if (r != null) {
  126. r.run();// 執行任務
  127. }
  128. finished_task++;
  129. r = null;
  130. }
  131. }
  132. // 停止工作,讓該線程自然執行完run方法,自然結束
  133. public void stopWorker() {
  134. isRunning = false;
  135. }
  136. }
  137. }
Copyright © Linux教程網 All Rights Reserved