線程池學習

 新建一個線程並啓動,開銷會很大,由於運行線程須要的資源比調用對象方法須要的資源多得多。在不少狀況下,線程被用於執行一類任務,而這類任務數量不少,發生的時間分佈不均,若是爲每一個新任務都啓用一個新線程來執行,則開銷會太大,能夠採用一種性能優化技術,就是使用線程池。java

  將若干執行任務的線程放在池中,當有任務要執行時,從池中取出一個空閒線程來處理任務,處理完任務後,再講線程對象放入池中。線程池實際上就是一個對象池,只是池中的對象都是線程。性能優化

  本文實例將實現一個線程池,能夠給線程池分配任務,線程池中的線程自動獲取任務並執行。ide

  關鍵技術:1.線程組ThreadGroup能夠管理多個線程,因此讓線程池繼承ThreadGroup。性能

       2.無條件關閉線程池時,經過ThreadGroup的interrupt方法中斷池中的全部線程。優化

       3.有條件關閉線程池時,經過ThreadGroup得到池中全部活動線程的引用,依次調用Thread的join方法等待活動線程執行完畢。當全部線程都運行結束時,線程池才                        能被關閉。this

       4.將任務放在LinkedList中,因爲LinkedList不支持同步,因此在添加任務和獲取任務的方法聲明中必須使用Synchronized關鍵字。線程

實例orm

package book.thread.pool;
/**
*定義任務的接口類
*/
public interface Task {
  public void perform() throws Exception;
}對象

package book.thread.pool;繼承

public class MyTask implements Task{
  private int taskID = 0;//任務ID
  public MyTask(int id){
    this.taskID = id;
  }

  @Override
  public void perform() throws Exception {
    System.out.println("MyTask " + taskID + ":start");
    Thread.sleep(1000);
    System.out.println("MyTask " + taskID + ":end");
  }
}

package book.thread.pool;

import java.util.LinkedList;

public class MyThreadPool extends ThreadGroup{
  private boolean isAlive;//標誌線程池是否開啓
  private LinkedList taskQueue;//線程池中的任務隊列
  private int threadID;//線程池中的線程ID
  private static int threadPoolID;//線程池ID
  //建立新的線程池,numThreads是池中的線程數
  public MyThreadPool(int numThreads){
    super("ThreadPool-"+(threadPoolID++));
    //設置該線程池的Daemon屬性爲true,表示當該線程池中的全部線程都被銷燬時,該線程池會自動被銷燬
    super.setDaemon(true);
    this.isAlive = true;
    this.taskQueue = new LinkedList();//新建一個任務隊列
    //啓動numThreads個工做線程
    for(int i = 0;i < numThreads; i++){
      new PooledThread().start();
    }
  }
  //添加新任務
  public synchronized void performTask(Task task){
    if(!this.isAlive){
      throw new IllegalStateException();//線程池被關閉,則拋出異常
    }
    if(task != null){
      this.taskQueue.add(task);//將任務放到任務隊列的尾部
      notify();//通知工做線程取任務
    }
  }
  //獲取任務
  protected synchronized Task getTask() throws InterruptedException{
    //若是任務列表爲空,並且線程池沒有被關閉,則繼續等待任務
    while(this.taskQueue.size() == 0){
      if(!this.isAlive){
        return null;
      }
      wait();
    }
    //取任務列表的第一個任務
    return (Task)this.taskQueue.removeFirst();
  }
  //關閉線程池,全部線程中止,再也不執行任務
  public synchronized void close(){
    if(isAlive){
      this.isAlive = false;
      this.taskQueue.clear();//清除任務
      this.interrupt();//停止線程池中的全部線程
    }
  }
  //關閉線程池,並等待線程池中的全部任務運行完成,但不能接收新任務
  public void join(){
    //通知其餘等待線程「該線程池已關閉」的消息
    synchronized(this){
      isAlive = false;
      notifyAll();
    }
  //等待全部線程完成,首先創建一個新的線程組,activeCount方法獲取線程池中活動線程的估計數
  Thread[] threads = new Thread[this.activeCount()];
  //將線程池中的活動線程拷貝到新建立的線程組threads中
  int count = this.enumerate(threads);
  for(int i = 0;i < count; i++){
    try {
      threads[i].join();//等待線程運行結束
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
}
//內部類,用於執行任務的工做線程
private class PooledThread extends Thread{
  public PooledThread(){
    //第一個參數爲該線程所在的線程組對象,即當前線程池對象
    //第二個參數爲線程名字
    super(MyThreadPool.this,"PooledThread-" +(threadID++));
  }
  public void run(){
    //若是該線程沒有被停止
    while(!isInterrupted()){
      //獲取任務
      Task task = null;
    try {
      task = getTask();
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    //只要線程池的任務列表不爲空,getTask方法就總能獲得一個任務
    //若getTask()返回null,則表示線程池中已經沒有任務,並且線程池已經被關閉
    if(task == null){
      return;
    }
    //運行任務,捕捉異常
    try {
      task.perform();
     } catch (Exception e) {
      uncaughtException(this,e);
     }
    }
  }
  }
}

package book.thread.pool;

public class PoolTest {
  public static void main(String[] args) {
    int numThreads = 3;//線程池中的線程數
    MyThreadPool threadPool = new MyThreadPool(numThreads);//生成線程池
    int numTasks = 10;//任務數
    //運行任務
    for(int i = 0;i<numTasks;i++){
      threadPool.performTask(new MyTask(i));
    }
    //關閉線程池並等待全部任務完成
    threadPool.join();
  }
}

輸出結果:

MyTask 0:start
MyTask 1:start
MyTask 2:start
MyTask 0:end
MyTask 3:start
MyTask 1:end
MyTask 4:start
MyTask 2:end
MyTask 5:start
MyTask 3:end
MyTask 6:start
MyTask 4:end
MyTask 7:start
MyTask 5:end
MyTask 8:start
MyTask 6:end
MyTask 9:start
MyTask 7:end
MyTask 8:end
MyTask 9:end

結果分析:MyThreadPool類是線程池的主體類,用於管理一組工做線程。

       1.繼承ThreadGroup,可使用ThreadGroup提供的方法管理線程池中的線程。

       2.performTask公有同步方法往線程池的任務隊列中添加一個任務。若是線程池已被關閉,即isAlive屬性爲false,則不容許添加任務;添加任務後,調用notify方                         法,通知池中的工做線程取任務。

       3.getTask受保護同步方法從線程池的任務隊列中獲取一個任務。之因此聲明爲受保護的,是爲了限制其餘類的對象非法獲取任務。若是任務隊列中沒有任務,則當                        前線程進入等待狀態,若是線程池已被關閉,則直接返回null。

       4.close方法強制關閉線程池。經過ThreadGroup的interrupt方法中斷線程池中全部運行的線程,清空任務隊列,而且isAlive屬性設置爲false,表示不接收新任務

       5.join方法有條件的關閉線程池。isAlive屬性置爲false,表示線程池再也不接收新任務,經過ThreadGroup得到正在運行的線程,經過Thread的join方法等待他們執                       行完任務後,再關閉線程池。

    PooledThread類是MyThreadPool的內部類,定義了工做線程,處於MyThreadPool線程池中。在run放在中不斷的從線程池的任務隊列中取任務,取到任務後,調用任務的perform方法執行任務。

相關文章
相關標籤/搜索