一、線程池簡介:
多線程技術主要解決處理器單元內多個線程執行的問題,它能夠顯著減小處理器單元的閒置時間,增長處理器單元的吞吐能力。
假設一個服務器完成一項任務所需時間爲:T1 建立線程時間,T2 在線程中執行任務的時間,T3 銷燬線程時間。
若是:T1 + T3 遠大於 T2,則能夠採用線程池,以提升服務器性能。
一個線程池包括如下四個基本組成部分:
一、線程池管理器(ThreadPool):用於建立並管理線程池,包括 建立線程池,銷燬線程池,添加新任務;
二、工做線程(PoolWorker):線程池中線程,在沒有任務時處於等待狀態,能夠循環的執行任務;
三、任務接口(Task):每一個任務必須實現的接口,以供工做線程調度任務的執行,它主要規定了任務的入口,任務執行完後的收尾工做,任務的執行狀態等;
四、任務隊列(taskQueue):用於存放沒有處理的任務。提供一種緩衝機制。
線程池技術正是關注如何縮短或調整T1,T3時間的技術,從而提升服務器程序性能的。它把T1,T3分別安排在服務器程序的啓動和結束的時間段或者一些空閒的時間段,這樣在服務器程序處理客戶請求時,不會有T1,T3的開銷了。
線程池不只調整T1,T3產生的時間段,並且它還顯著減小了建立線程的數目,看一個例子:
假設一個服務器一天要處理50000個請求,而且每一個請求須要一個單獨的線程完成。在線程池中,線程數通常是固定的,因此產生線程總數不會超過線程池中線程的數目,而若是服務器不利用線程池來處理這些請求則線程總數爲50000。通常線程池大小是遠小於50000。因此利用線程池的服務器程序不會爲了建立50000而在處理請求時浪費時間,從而提升效率。java
代碼實現中並無實現任務接口,而是把Runnable對象加入到線程池管理器(ThreadPool),而後剩下的事情就由線程池管理器(ThreadPool)來完成了安全
[java] view plaincopy服務器
- package mine.util.thread;
-
- import java.util.LinkedList;
- import java.util.List;
-
- /**
- * 線程池類,線程管理器:建立線程,執行任務,銷燬線程,獲取線程基本信息
- */
- public final class ThreadPool {
- // 線程池中默認線程的個數爲5
- private static int worker_num = 5;
- // 工做線程
- private WorkThread[] workThrads;
- // 未處理的任務
- private static volatile int finished_task = 0;
- // 任務隊列,做爲一個緩衝,List線程不安全
- private List<Runnable> taskQueue = new LinkedList<Runnable>();
- private static ThreadPool threadPool;
-
- // 建立具備默認線程個數的線程池
- private ThreadPool() {
- this(5);
- }
-
- // 建立線程池,worker_num爲線程池中工做線程的個數
- private ThreadPool(int worker_num) {
- ThreadPool.worker_num = worker_num;
- workThrads = new WorkThread[worker_num];
- for (int i = 0; i < worker_num; i++) {
- workThrads[i] = new WorkThread();
- workThrads[i].start();// 開啓線程池中的線程
- }
- }
-
- // 單態模式,得到一個默認線程個數的線程池
- public static ThreadPool getThreadPool() {
- return getThreadPool(ThreadPool.worker_num);
- }
-
- // 單態模式,得到一個指定線程個數的線程池,worker_num(>0)爲線程池中工做線程的個數
- // worker_num<=0建立默認的工做線程個數
- public static ThreadPool getThreadPool(int worker_num1) {
- if (worker_num1 <= 0)
- worker_num1 = ThreadPool.worker_num;
- if (threadPool == null)
- threadPool = new ThreadPool(worker_num1);
- return threadPool;
- }
-
- // 執行任務,其實只是把任務加入任務隊列,何時執行有線程池管理器覺定
- public void execute(Runnable task) {
- synchronized (taskQueue) {
- taskQueue.add(task);
- taskQueue.notify();
- }
- }
-
- // 批量執行任務,其實只是把任務加入任務隊列,何時執行有線程池管理器覺定
- public void execute(Runnable[] task) {
- synchronized (taskQueue) {
- for (Runnable t : task)
- taskQueue.add(t);
- taskQueue.notify();
- }
- }
-
- // 批量執行任務,其實只是把任務加入任務隊列,何時執行有線程池管理器覺定
- public void execute(List<Runnable> task) {
- synchronized (taskQueue) {
- for (Runnable t : task)
- taskQueue.add(t);
- taskQueue.notify();
- }
- }
-
- // 銷燬線程池,該方法保證在全部任務都完成的狀況下才銷燬全部線程,不然等待任務完成才銷燬
- public void destroy() {
- while (!taskQueue.isEmpty()) {// 若是還有任務沒執行完成,就先睡會吧
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- // 工做線程中止工做,且置爲null
- for (int i = 0; i < worker_num; i++) {
- workThrads[i].stopWorker();
- workThrads[i] = null;
- }
- threadPool=null;
- taskQueue.clear();// 清空任務隊列
- }
-
- // 返回工做線程的個數
- public int getWorkThreadNumber() {
- return worker_num;
- }
-
- // 返回已完成任務的個數,這裏的已完成是隻出了任務隊列的任務個數,可能該任務並無實際執行完成
- public int getFinishedTasknumber() {
- return finished_task;
- }
-
- // 返回任務隊列的長度,即還沒處理的任務個數
- public int getWaitTasknumber() {
- return taskQueue.size();
- }
-
- // 覆蓋toString方法,返回線程池信息:工做線程個數和已完成任務個數
- @Override
- public String toString() {
- return "WorkThread number:" + worker_num + " finished task number:"
- + finished_task + " wait task number:" + getWaitTasknumber();
- }
-
- /**
- * 內部類,工做線程
- */
- private class WorkThread extends Thread {
- // 該工做線程是否有效,用於結束該工做線程
- private boolean isRunning = true;
-
- /*
- * 關鍵所在啊,若是任務隊列不空,則取出任務執行,若任務隊列空,則等待
- */
- @Override
- public void run() {
- Runnable r = null;
- while (isRunning) {// 注意,若線程無效則天然結束run方法,該線程就沒用了
- synchronized (taskQueue) {
- while (isRunning && taskQueue.isEmpty()) {// 隊列爲空
- try {
- taskQueue.wait(20);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- if (!taskQueue.isEmpty())
- r = taskQueue.remove(0);// 取出任務
- }
- if (r != null) {
- r.run();// 執行任務
- }
- finished_task++;
- r = null;
- }
- }
-
- // 中止工做,讓該線程天然執行完run方法,天然結束
- public void stopWorker() {
- isRunning = false;
- }
- }
- }
測試代碼:多線程
[java] view plaincopyapp
- package mine.util.thread;
-
- //測試線程池
- public class TestThreadPool {
- public static void main(String[] args) {
- // 建立3個線程的線程池
- ThreadPool t = ThreadPool.getThreadPool(3);
- t.execute(new Runnable[] { new Task(), new Task(), new Task() });
- t.execute(new Runnable[] { new Task(), new Task(), new Task() });
- System.out.println(t);
- t.destroy();// 全部線程都執行完成才destory
- System.out.println(t);
- }
-
- // 任務類
- static class Task implements Runnable {
- private static volatile int i = 1;
-
- @Override
- public void run() {// 執行任務
- System.out.println("任務 " + (i++) + " 完成");
- }
- }
- }
運行結果:ide
WorkThread number:3 finished task number:0 wait task number:6
任務 1 完成
任務 2 完成
任務 3 完成
任務 4 完成
任務 5 完成
任務 6 完成
WorkThread number:3 finished task number:6 wait task number:0性能
分析:因爲並無任務接口,傳入的能夠是自定義的任何任務,因此線程池並不能準確的判斷該任務是否真正的已經完成(真正完成該任務是這個任務的run方法執行完畢),只能知道該任務已經出了任務隊列,正在執行或者已經完成。測試
二、Java類庫中提供的線程池簡介:this
java提供的線程池更增強大,相信理解線程池的工做原理,看類庫中的線程池就不會感到陌生了。spa
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)