使用ThreadGroup模擬執行緒池
參考文章:
[1]建立執行緒池 http://sunnylocus.iteye.com/blog/223327?page=2#comments
[2]執行緒組ThreadGroup http://hubingforever.blog.163.com/blog/static/1710405792010913191791/
一、為什麼要用執行緒池:
1)減少了建立和銷燬執行緒的次數,每個工作執行緒都可以被重複利用,可執行多個任務
2)可以根據系統的承受能力,調整執行緒池中工作執行緒的數目,防止因為消耗過多的記憶體,而把伺服器累趴下(每個執行緒需要大約1MB記憶體,執行緒開的越多,消耗的記憶體也就越大,最後宕機)
二、ThreadGroup類介紹
1.概括:
1)ThreadGroup執行緒組表示一個執行緒的集合。
2)此外,執行緒組也可以包含其他執行緒組。
3)執行緒組構成一棵樹,在樹中,除了初始執行緒組外,每個執行緒組都有一個父執行緒組。
4)允許執行緒訪問有關自己的執行緒組的資訊,但是不允許它訪問有關其執行緒組的父執行緒組或其他任何執行緒組的資訊。
2.在Java中每個執行緒都屬於某個執行緒組(ThreadGroup)。
例如,如果在main()中產生一個執行緒,則這個執行緒屬於main執行緒組(其名字為"main")管理的一員,您可以使用下面的指令來獲得目前執行緒所屬的執行緒組名稱:
Thread.currentThread().getThreadGroup().getName();
3.每一個執行緒產生時,都會被歸入某個執行緒組,視執行緒是在哪個執行緒組中產生而定。如果沒有指定,則歸入產生該子執行緒的執行緒所在的執行緒組中。
您也可以自行指定執行緒組,執行緒一旦歸入某個組,就無法更換組。
java.lang.ThreadGroup類正如其名,可以統一管理整個執行緒組中的執行緒,您可以使用以下方式來產生執行緒組,而且一併指定其執行緒組:
ThreadGroup threadGroup1 = newThreadGroup("group1"); ThreadGroup threadGroup2 = newThreadGroup("group2"); Thread thread1 =new Thread(threadGroup1,"group1's member"); Thread thread2 =new Thread(threadGroup2,"group2's member");
4.ThreadGroup中的某些方法,可以對所有的執行緒產生作用,例如interrupt()方法可以interrupt執行緒組中所有的執行緒,
setMaxPriority()方法可以設定執行緒組中執行緒所能擁有的最高優先權(本來就擁有更高優先權的執行緒不受影響)。
5.如果您想要一次獲得執行緒組中所有的執行緒來進行某種操作,可以使用enumerate()方法,例如:
Thread[] threads = newThread[threadGroup1.activeCount()];
threadGroup1.enumerate(threads);
activeCount()方法獲得執行緒組中正在執行的執行緒數量,enumerate()方法要傳入一個Thread陣列,
它將執行緒物件設定到每個陣列欄位中,然後就可以通過陣列索引來操作這些執行緒。
6.ThreadGroup中有一個uncaughtException()方法。當執行緒組中某個執行緒發生Unchecked exception異常時,由執行環境呼叫此方法進行相關處理,如果有必要,您可以重新定義此方法。
7.構造方法
public ThreadGroup(String name)
構造一個新執行緒組。新執行緒組的父執行緒組是目前正在執行執行緒的執行緒組。 不使用任何引數呼叫父執行緒組的 checkAccess 方法;這可能導致一個安全性異常。
引數:
name - 新執行緒組的名稱。
丟擲:
SecurityException - 如果當前執行緒不能在指定的執行緒組中建立執行緒。
public ThreadGroup(ThreadGroupparent,String name)
建立一個新執行緒組。新執行緒組的父執行緒組是指定的執行緒組。
不使用任何引數呼叫父執行緒組的 checkAccess 方法;這可能導致一個安全性異常。
引數:
parent - 父執行緒組。
name - 新執行緒組的名稱。
丟擲:
NullPointerException - 如果執行緒組引數為 null。
SecurityException - 如果當前執行緒不能在指定的執行緒組中建立執行緒。
三、執行緒池類模擬程式碼:
package com.tdt.impl.ls;
import java.util.LinkedList;
/**
* @project LocationGateway
* @author sunnylocus
* @verson 1.0.0
* @date Aug 2, 2008
* @jdk 1.4.2
*/
public class ThreadPool extends ThreadGroup {
private boolean isClosed = false; //執行緒池是否關閉
private LinkedList workQueue; //工作佇列
private static int threadPoolID = 1; //執行緒池的id
public ThreadPool(int poolSize) { //poolSize 表示執行緒池中的工作執行緒的數量
super(threadPoolID + ""); //指定ThreadGroup的名稱
setDaemon(true); //繼承到的方法,設定是否守護執行緒池
workQueue = new LinkedList(); //建立工作佇列
for(int i = 0; i < poolSize; i++) {
new WorkThread(i).start(); //建立並啟動工作執行緒,執行緒池數量是多少就建立多少個工作執行緒
}
}
/** 向工作佇列中加入一個新任務,由工作執行緒去執行該任務*/
public synchronized void execute(Runnable task) {
if(isClosed) {
throw new IllegalStateException();
}
if(task != null) {
workQueue.add(task);//向佇列中加入一個任務
notify(); //喚醒一個正在getTask()方法中待任務的工作執行緒
}
}
/** 從工作佇列中取出一個任務,工作執行緒會呼叫此方法*/
private synchronized Runnable getTask(int threadid) throws InterruptedException {
while(workQueue.size() == 0) {
if(isClosed) return null;
System.out.println("工作執行緒"+threadid+"等待任務...");
wait(); //如果工作佇列中沒有任務,就等待任務
}
System.out.println("工作執行緒"+threadid+"開始執行任務...");
return (Runnable) workQueue.removeFirst(); //反回佇列中第一個元素,並從佇列中刪除
}
/** 關閉執行緒池 */
public synchronized void closePool() {
if(! isClosed) {
waitFinish(); //等待工作執行緒執行完畢
isClosed = true;
workQueue.clear(); //清空工作佇列
interrupt(); //中斷執行緒池中的所有的工作執行緒,此方法繼承自ThreadGroup類
}
}
/** 等待工作執行緒把所有任務執行完畢*/
public void waitFinish() {
synchronized (this) {
isClosed = true;
notifyAll(); //喚醒所有還在getTask()方法中等待任務的工作執行緒
}
Thread[] threads = new Thread[activeCount()];
int count = enumerate(threads);
for(int i =0; i < count; i++) { //等待所有工作執行緒結束
try {
threads[i].join(); //等待工作執行緒結束
}catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
/**
* 內部類,工作執行緒,負責從工作佇列中取出任務,並執行
* @author sunnylocus
*/
private class WorkThread extends Thread {
private int id;
public WorkThread(int id) {
//父類構造方法,將執行緒加入到當前ThreadPool執行緒組中
super(ThreadPool.this,id+"");
this.id =id;
}
public void run() {
while(! isInterrupted()) { //isInterrupted()方法繼承自Thread類,判斷執行緒是否被中斷
Runnable task = null;
try {
task = getTask(id); //取出任務
}catch(InterruptedException ex) {
ex.printStackTrace();
}
//如果getTask()返回null或者執行緒執行getTask()時被中斷,則結束此執行緒
if(task == null) return;
try {
task.run(); //執行任務
}catch(Throwable t) {
t.printStackTrace();
}
}// end while
}// end run
}// end workThread
}