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)來完成了
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;
}
}
}
測試代碼:
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++) + " 完成");
}
}
}
運行結果:
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方法執行完畢),只能知道該任務已經出了任務隊列,正在執行或者已經完成。
2、java類庫中提供的線程池簡介:
java提供的線程池更加強大,相信理解線程池的工作原理,看類庫中的線程池就不會感到陌生了。