JAVAマルチスレッドの拡張ThreadPoolExecutor


ThreadPoolExecuterは拡張性があり、ソースコードを表示することで、サブクラス化で書き換える方法がいくつか提供されていることがわかります.beforeExecute、afterExecute、terminated.
ソースクリップは次のようになります.
protected void beforeExecute(Thread t, Runnable r) { }
protected void afterExecute(Runnable r, Throwable t) { }
protected void terminated() { }

この3つの方法はいずれもproptectedの空の方法であり,サブクラスを拡張させるものであることが明らかになったことに気づく.
タスクを実行するスレッドでは、beforeExecuteやafterExecuteなどのメソッドが呼び出され、ログ、タイミング、監視、統計収集の機能を追加することもできます.タスクがrunから正常に返されるか、例外を投げ出して返されるかにかかわらず、afterExecuteが呼び出されます.タスクが完了した後にErrorを持つ場合、afterExecuteは呼び出されません.beforeExecuteがRuntimeExceptionを投げ出すと、タスクは実行されず、afterExecuteも呼び出されません.
スレッドプールがシャットダウンを完了するとterminatedが呼び出されます.つまり、すべてのタスクが完了し、すべての作業者スレッドがシャットダウンされた後、terminatedはExecutorがライフサイクルで割り当てたさまざまなリソースを解放するために使用できます.また、通知の送信、ログの記録、携帯電話のfinalize統計などの操作も実行できます.
次に、スレッドプールに統計情報を追加する例(ログの追加やタイムリーな機能)を示します.
package com.threadPool;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Logger;

public class TimingThreadPool extends ThreadPoolExecutor
{
	private final ThreadLocal<Long> startTime = new ThreadLocal<Long>();
	private final Logger log = Logger.getAnonymousLogger();
	private final AtomicLong numTasks = new AtomicLong();
	private final AtomicLong totalTime = new AtomicLong();
	
	public TimingThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue<Runnable> workQueue)
	{
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
	}

	protected void beforeExecute(Thread t, Runnable r){
		super.beforeExecute(t, r);
		log.info(String.format("Thread %s: start %s", t,r));
		startTime.set(System.nanoTime());
	}
	
	protected void afterExecute(Runnable r, Throwable t){
		try{
			long endTime = System.nanoTime();
			long taskTime = endTime-startTime.get();
			numTasks.incrementAndGet();
			totalTime.addAndGet(taskTime);
			log.info(String.format("Thread %s: end %s, time=%dns", t,r,taskTime));
		}
		finally
		{
			super.afterExecute(r, t);
		}
	}
	
	protected void terminated()
	{
		try
		{
			log.info(String.format("Terminated: avg time=%dns",totalTime.get()/numTasks.get()));
		}
		finally
		{
			super.terminated();
		}
	}
}

TimingThreadPoolが親の3つのメソッドを書き換えていることがわかります.
次のテストクラスを作成します.実行効果を参照してください.
package com.threadPool;

import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CheckTimingThreadPool
{
	public static void main(String[] args)
	{
		ThreadPoolExecutor  exec = new TimingThreadPool(0, Integer.MAX_VALUE,
                60L, TimeUnit.SECONDS,
                new SynchronousQueue<Runnable>());
		exec.execute(new DoSomething(5));
		exec.execute(new DoSomething(4));
		exec.execute(new DoSomething(3));
		exec.execute(new DoSomething(2));
		exec.execute(new DoSomething(1));
		exec.shutdown();
	}

}

class DoSomething implements Runnable{
	private int sleepTime;
	public DoSomething(int sleepTime)
	{
		this.sleepTime = sleepTime;
	}
	@Override
	public void run()
	{
		System.out.println(Thread.currentThread().getName()+" is running.");
		try
		{
			TimeUnit.SECONDS.sleep(sleepTime);
		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
	}
	
}

実行結果:
    25, 2015 4:18:42    com.threadPool.TimingThreadPool beforeExecute
  : Thread Thread[pool-1-thread-1,5,main]: start com.threadPool.DoSomething@43f459c2
    25, 2015 4:18:42    com.threadPool.TimingThreadPool beforeExecute
  : Thread Thread[pool-1-thread-3,5,main]: start com.threadPool.DoSomething@33891d5d
pool-1-thread-3 is running.
    25, 2015 4:18:42    com.threadPool.TimingThreadPool beforeExecute
  : Thread Thread[pool-1-thread-4,5,main]: start com.threadPool.DoSomething@33891d5d
pool-1-thread-4 is running.
    25, 2015 4:18:42    com.threadPool.TimingThreadPool beforeExecute
  : Thread Thread[pool-1-thread-5,5,main]: start com.threadPool.DoSomething@10747b4
pool-1-thread-5 is running.
    25, 2015 4:18:42    com.threadPool.TimingThreadPool beforeExecute
  : Thread Thread[pool-1-thread-2,5,main]: start com.threadPool.DoSomething@7d4af469
pool-1-thread-2 is running.
pool-1-thread-1 is running.
    25, 2015 4:18:43    com.threadPool.TimingThreadPool afterExecute
  : Thread null: end com.threadPool.DoSomething@10747b4, time=999589906ns
    25, 2015 4:18:44    com.threadPool.TimingThreadPool afterExecute
  : Thread null: end com.threadPool.DoSomething@33891d5d, time=1999461618ns
    25, 2015 4:18:45    com.threadPool.TimingThreadPool afterExecute
  : Thread null: end com.threadPool.DoSomething@33891d5d, time=3000507593ns
    25, 2015 4:18:46    com.threadPool.TimingThreadPool afterExecute
  : Thread null: end com.threadPool.DoSomething@7d4af469, time=3999691253ns
    25, 2015 4:18:47    com.threadPool.TimingThreadPool afterExecute
  : Thread null: end com.threadPool.DoSomething@43f459c2, time=4999778490ns
    25, 2015 4:18:47    com.threadPool.TimingThreadPool terminated
  : Terminated: avg time=2999805772ns

テストクラスCheckTimingThreadPoolでexecuteを介して5つのスレッドを統計し,各スレッドの平均時間を統計したことがわかる.
ここではTimingThreadPoolのコンストラクション関数を説明します.親クラスのコンストラクションメソッドを直接呼び出します.ThreadPoolExecutorにはコンストラクションメソッドがたくさんあります.興味のある方はjdk apiまたはソースコードを表示して表示できます.
関数を構成するパラメータの意味を簡単に説明します.
CorePoolSize:スレッドプールメンテナンススレッドの最小数
maximumPoolSize:スレッドプールメンテナンススレッドの最大数
keepAliveTime:スレッドプールメンテナンススレッドによって許可されるアイドル時間
unit:スレッドプールメンテナンスで許容されるアイドル時間の単位
workQueue:スレッドプールで使用されるキャッシュキュー