JDK1.5のスレッドプールの使用概要

4687 ワード

マルチスレッドマスターDoug Leaの貢献でJDK 1.5には、スレッドプールなどの同時プロパティのサポートが多数追加されています.
 
一、紹介
スレッドプールクラスはjavaです.util.concurrent.ThreadPoolExecutor、一般的な構造方法は次のとおりです.
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler)
CorePoolSize:スレッドプールメンテナンススレッドの最小数
maximumPoolSize:スレッドプールメンテナンススレッドの最大数
keepAliveTime:スレッドプールメンテナンススレッドによって許可されるアイドル時間
unit:スレッドプールメンテナンススレッドが許可するアイドル時間の単位
workQueue:スレッドプールで使用されるバッファキュー
handler:スレッドプールによるタスク拒否の処理ポリシー
1つのタスクはexecute(Runnable)メソッドによってスレッドプールに追加され、タスクはRunnableタイプのオブジェクトであり、タスクの実行方法はRunnableタイプのオブジェクトのrun()メソッドである.
タスクをexecute(Runnable)メソッドでスレッドプールに追加する場合:
スレッドプールの数がcorePoolSizeより小さい場合は、スレッドプールのスレッドがアイドル状態であっても、追加されたタスクを処理するために新しいスレッドを作成します.
スレッドプールの数がcorePoolSizeに等しいが、バッファキューworkQueueが満たされていない場合、タスクはバッファキューに格納されます.
このとき、スレッドプールの数がcorePoolSizeより大きい場合、バッファキューworkQueueがいっぱいで、スレッドプールの数がmaximumPoolSizeより小さい場合は、追加されたタスクを処理するために新しいスレッドを作成します.
スレッドプールの数がcorePoolSizeより大きく、バッファキューworkQueueがいっぱいで、スレッドプールの数がmaximumPoolSizeに等しい場合は、handlerが指定したポリシーによってこのタスクを処理します.
つまり、タスクの優先順位は次のとおりです.
コアスレッドcorePoolSize、タスクキューworkQueue、最大スレッドmaximumPoolSizeの3つが満たされている場合は、拒否されたタスクをhandlerで処理します.
スレッドプール内のスレッド数がcorePoolSizeより大きい場合、あるスレッドのアイドル時間がkeepAliveTimeを超えると、スレッドは終了します.これにより、スレッドプールは、プール内のスレッド数を動的に調整することができる.
unitオプションのパラメータはjavaです.util.concurrent.TimeUnitの静的プロパティ:
NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS.
私がよく使うのはjavaです.util.concurrent.ArrayBlockingQueue
handlerには4つの選択肢があります.
ThreadPoolExecutor.AbortPolicy()
javaを投げ出すutil.concurrent.RejectedExecutionException異常
ThreadPoolExecutor.CallerRunsPolicy()
現在のタスクを追加し直すと、execute()メソッドが自動的に繰り返し呼び出されます.
ThreadPoolExecutor.DiscardOldestPolicy()
古い任務を捨てる
ThreadPoolExecutor.DiscardPolicy()
当面の任務を投げ捨てる
 
二、一般用法例
import java.io.Serializable;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestThreadPool {

	private static int produceTaskSleepTime = 2;

	private static int consumeTaskSleepTime = 2000;

	private static int produceTaskMaxNumber = 10;

	public static void main(String[] args) {

		//  
		ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 4, 3,
				TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(3),
				new ThreadPoolExecutor.DiscardOldestPolicy());

		for (int i = 1; i <= produceTaskMaxNumber; i++) {
			try {
				//  , 
				String task = "task@ " + i;
				System.out.println("put " + task);
				threadPool.execute(new ThreadPoolTask(task));

				//  , 
				Thread.sleep(produceTaskSleepTime);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 *  
	 * 
	 * @author hdpan
	 */
	public static class ThreadPoolTask implements Runnable, Serializable {
		private static final long serialVersionUID = 0;

		//  
		private Object threadPoolTaskData;

		ThreadPoolTask(Object tasks) {
			this.threadPoolTaskData = tasks;
		}

		public void run() {
			//  , , 
			System.out.println("start .." + threadPoolTaskData);
			try {
				// // , 
				Thread.sleep(consumeTaskSleepTime);
			} catch (Exception e) {
				e.printStackTrace();
			}
			threadPoolTaskData = null;
		}

		public Object getTask() {
			return this.threadPoolTaskData;
		}
	}
}
 
説明:
1、このプログラムでは、1つのタスクはRunnableタイプのオブジェクト、つまりThreadPoolTaskタイプのオブジェクトです.
2、一般的にタスクは処理方式のほかに、処理するデータが必要であり、処理するデータは構造方法によってタスクに伝達される.
3、このプログラムの中で、main()の方法は残忍な指導者に相当して、彼は多くの任務を派遣して、threadPoolという任労任怨のグループに捨ててやります.
このグループには少なくとも2人の選手がいて、もし彼ら2人が忙しくて来られないならば、任務は任務リストに入れられます.
溜まったクエストが多すぎて、クエストリストに入れられない(3個を超える)ほど多い場合は、新しい隊員を雇って手伝います.しかし、コストを考慮すると、多くの隊員を雇うことはできず、せいぜい4人しか雇うことができない.
もし4人の隊員がすべて忙しい時、更に新しい任務があれば、このグループは処理できなくて、任務は1種の策略を通じて処理されて、私達の処理方式は絶えず配布して、この任務を受け入れるまで(更に残忍です!ほほほ).
メンバーの仕事にはコストがかかるので、仕事が暇で、3 SECONDSまで暇で新しい任務がないと、解雇されるメンバーもいますが、グループの正常な運営のために、いくら仕事が暇でも、グループのメンバーは2人以上ではありません.
4、produceTaskSleepTimeとconsumeTaskSleepTimeのサイズを調整することで、配布タスクと処理タスクの速度の制御を実現し、この2つの値を変更することで、異なるレートでのプログラムの動作状況を観察することができる.
5、4に示すデータを調整し、さらにタスク破棄ポリシーを調整し、他の3つのポリシーに置き換えることで、異なるポリシーの下での異なる処理方式を見ることができます.
6、その他の使用方法については、jdkの助けを参照して、理解しやすく使用します.