1. 程式人生 > >關於java執行緒池的一丟丟

關於java執行緒池的一丟丟

執行緒池應用達到的目的

1、降低資源消耗;可以重複利用已建立的執行緒從而降低執行緒建立和銷燬所帶來的消耗。

2、提高響應速度;當任務到達時,不需要等執行緒建立就可以立即執行。

3、提高執行緒的可管理性;使用執行緒池統一分配、調優和監控。

  • 執行緒池實現原理 

        1、 最核心的ThreadPoolExecutor類,ThreadPoolExecutor、AbstractExecutorService、ExecutorService和Executor幾個之間的關係

         public

 class ThreadPoolExecutor extends AbstractExecutorService {

                                 public abstract class AbstractExecutorService implements ExecutorService {             

                                                            public interface ExecutorService extends Executor {

                                                                                        public

 interface Executor {

                                        void  execute(Runnable command);                                         }          以上繼承關係;   ExecutorService介面繼承了Executor介面,並聲明瞭一些方法:submit、invokeAll、invokeAny以及shutDown等;               2、ThreadPoolExecutor 實現 Executor介面的邏輯          原始碼分析:
a、當執行執行緒少於corePoolSize,則建立新執行緒來執行任務
b、當執行執行緒等於或大於corePoolSize ,則將任務加入BlockingQueue(任務快取佇列,用於存放等待執行任務)
c、BlockingQueue 佇列已經滿了而無法加入任務,必須獲取全域性鎖從而建立新的執行緒來處理任務
d、建立新執行緒將使當前執行的執行緒超出maximumPoolSize,任務將被拒絕,並呼叫RejectedExecutionException()方法,丟擲異常
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
        if (runState == RUNNING && workQueue.offer(command)) {
            if (runState != RUNNING || poolSize == 0)
                ensureQueuedTaskHandled(command);
        }
        else if (!addIfUnderMaximumPoolSize(command))
       //丟擲RejectedExecutionException異常 reject(command);
// is shutdown or saturated } }
  • 執行緒池的使用

       new ThreadPoolExecutor(corePoolSize, maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,handler);

       這裡解釋一下入參含義

       corePoolSize 設定執行緒池的基本大小,

  maximumPoolSize  設定執行緒池最大能建立的執行緒數多少

       keepAliveTime   執行緒活動儲存時間,也就是工作執行緒完成後還繼續存活的時間,有必要時單個任務完成時間短,可把存活時間設大保持較高執行緒利用率;

       milliseconds  毫秒-執行緒活動保持時間的單位 可以是days\hours\等等

  runnableTaskQueue 任務佇列,用於儲存等待執行的任務的阻塞佇列

            runnableTaskQueue 的型別為BlockingQueue<Runnable>,通常可以取下面三種類型:

  1)ArrayBlockingQueue:基於陣列的先進先出佇列,此佇列建立時必須指定大小;

  2)LinkedBlockingQueue:基於連結串列的先進先出佇列,如果建立時沒有指定此佇列大小,則預設為Integer.MAX_VALUE;

  3)synchronousQueue:這個佇列比較特殊,它不會儲存提交的任務,而是將直接新建一個執行緒來執行新來的任務。

       4)PriorityBlockingQueue:一個具有優先順序的無限阻塞佇列

demo例子

public class Test {
     public static void main(String[] args) {   
         ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
                 new ArrayBlockingQueue<Runnable>(5));
          
         for(int i=0;i<15;i++){
             MyTask myTask = new MyTask(i);
             executor.execute(myTask);
             System.out.println("執行緒池中執行緒數目:"+executor.getPoolSize()+",佇列中等待執行的任務數目:"+
             executor.getQueue().size()+",已執行玩別的任務數目:"+executor.getCompletedTaskCount());
         }
         executor.shutdown();
     }
}
 
 
class MyTask implements Runnable {
    private int taskNum;
     
    public MyTask(int num) {
        this.taskNum = num;
    }
     
    @Override
    public void run() {
        System.out.println("正在執行task "+taskNum);
        try {
            Thread.currentThread().sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task "+taskNum+"執行完畢");
    }
}