独自のスレッドプールを実装
ケース内には、自分自身を見までのGitHubからダウンロードすることができ
Juc-MyExecutorで//github.com/JolyouLu/Juc-study.gitコードます。https:アドレス
スレッドプールの性質
私たちは、新しいスレッドが作成し、使用するスレッド場合、スレッドは、より良い、開いていないときに我々は、スレッドプールの性質を理解する必要があり、プールがやっているスレッドを実装する前に、彼は複数のスレッドを使用することで問題を解決しCG(ガベージコレクション)の周波数まで新しいヒープ簡単にフルスピードの、頻繁に使用し、再利用することができない、すべてのCG JVMは、望ましい結果を取得していないマルチスレッド、彼はかなりいたスレッドプールを利用して、CGの終了を待っているすべての作業を停止しますマルチスレッドのコンテナ、スレッドプールのスレッドが再利用できるように、スレッド、余分なスレッドやその他の問題解決戦略の数を待って、実行中のスレッドの現在の数を制御することができます。
スレッドプールのメタファー
私たちは、私たちが知っている必要があり、すべての最初の、私たちは工場を行うには、プールのメタファーを通すことができますどのようなスレッドプールのニーズ、実現するために、あなたはそれが必要なもののラインを開きたいボス、原材料機械、正式な仕事の数、一時的なものであることをスレッドプールを達成したいです労働者の数、給与所得状況は、単一の戦略を拒否します
生機:農産物加工する必要原料があるので、スレッドを実行します、かなりの生産スレッドがある限りは、長い間、労働者がいる限り、原料は組み立てに取得する必要があります
人々の完全な場合、原材料は地域に積層され、それはあなたが上司であればあなたが必要ということであれば、その領域は、原料で満たされているように、機械の原料生産速度が速く、組立作業員の速度よりも確かにあり、正式な労働者:原材料は、ステージングエリアいくつかの一時的な労働者を雇う考慮し、コアスレッドがいっぱいの場合、かなりのスレッドプールのキューは、タスクはキューがいっぱいの場合、将来は、新しいスレッドの実行を作成し、キューに追加されます
フォーマル労働者:正式な長期的な作業は、スレッドプールのタスクは、バックグラウンドでコアスレッドRAN上で実行された場合でも、あなたが仕事に非常にコア能力を持っているすべてのジョブを仕事に行くことはまだ空であります
一時的:あなたは突然仕事は、スレッドプールの最大容量に相当する植物は、一時的な労働者、派遣労働者を雇用し、恒久的な労働者が異なるタスクが起動されます終えたので、それは、高速であることへのワークロードの場合
ワーカーのステータス:、これらの正式な労働者は、これらの日を仕事に来るが、彼らを解雇したとみなされていないすべての作業を行う必要がない場合には、資本の破壊を減らします
単一の戦略を拒否した:私たちの原材料ステージング領域がいっぱいになった場合、また、物事を行うようにするには、手の上に、一時的な労働者がいっぱい、それは原料を停止するために新規受注を受け入れることを拒否すべきである労働者を募集する原材料の無駄を避けるために、
JDKのスレッドプール
上記類推した後、私たちは、JDKのスレッド・プール・インターフェースを見て
public ThreadPoolExecutor(int corePoolSize, //核心容量
int maximumPoolSize, //最大容量
long keepAliveTime, //超时时间
TimeUnit unit, //时间单位
BlockingQueue<Runnable> workQueue) { //线程队列
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
私の最初のAスレッドプール
//我这里初始了一个 核心容量是10 最大容量是50 核心线程空闲0秒就去处 LinkedBlockingQueue队列的线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 50, 0L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
私たちはすべて理解して信じているタイムアウトスレッドのコア容量の最大容量、その後、私はキューことをここで言いたいです
JDKスレッドプールキュー
ArrayBlockingQueue:現在のスレッドがキューも一杯になった場合にコアタスクは、その後、待ち行列に参加する上で実行している場合は、長さを渡す必要を作成するとき、あなたはキューの長さを定義することができ、受信タスクは、CPUは一時的な作成しますスレッドミッション、容量、エラーが発生したスレッドの最大数よりも一時的なオープンより多くのことであれば
LinkedBlockingQueue:これはアンバウンド形式のキュー、キューの長さが無限であるInteger.MAX_VALUEで、ですが、現在のスレッドは、キューに参加するコアタスク上で実行された場合、このキューは無限であるので、その後、それがいっぱいになることはありません唯一のキューがいっぱいCPUスレッドは一時的なミッションを作成するために行くだろうが、あなたはキューいっぱいであることは決してありませんので、キューを使用した後、あなたが最大容量を設定した後ことを意味することは、無意味です
SynchronousQueue:この同期キュー、キューは単に単純に長さではありませんが、それは一見に入れなかったキューは、単に容量ではないので、任意のタスクに合わせて、現在のコアスレッドがフル実行している場合、このキューフィット何かが、それは容量、エラーが発生したことを、スレッドの最大数よりもあれば、一時的なオープンより多くのを一時的にスレッドのCPUタスクを作成します。
DelayQueue:キュー要素内の遅延は、まず最初に、チームの唯一の指定された遅延時間に達し、タスクを実行し、キューがタスクを受信しているときにタスクを渡す意味インタフェースは、遅延インターフェースを実装する必要があります実装する必要があります
プールワークフロースレッド
コアがフルコアスレッドならば、それは、タスクがコアスレッドに追加されたメソッドaddWorkを呼び出しますフル稼働でない場合はまず、メインスレッド(メイン)はメソッド呼び出しを実行します、我々は、任意の裁判官に、現在のスレッドプールのコア能力の一部を移動しますタスクは、キューはまた、非中核船ならば、これは、これらのタスクを実行するための非中核コンテナの容量を作成するまで満たされた場合にコアスレッドは、キューから取り出し中に空きがあるのを待っている、私たちの待ち行列に提供していきますフルその後、来てタスクを持って、戦略を使用することを拒否します
独自のスレッドプールを実装
エグゼキュータ・インターフェース
インターフェイスは実行提供するすべてのスレッドプールの基本クラス
public interface Executor {
void execute(Runnable task);
}
ThreadPoolExecutor実装クラス
私は、多層継承を使用していなかったので、実現するのは簡単であるため、
public class ThreadPoolExecutor implements Executor {
//核心容量
private volatile int corePollSize;
//最大容量
private volatile int maximumPoolSize;
//核心线程超时销毁
private volatile long keepAliveTime;
//描述是否需要超时销毁
private volatile boolean allowCoreThreadTimeOut;
//当前数量
private final AtomicInteger ctl = new AtomicInteger(0);
//队列
private BlockingQueue<Runnable> workQueue;
//初始线程池
public ThreadPoolExecutor(int corePollSize, int maximumPoolSize, BlockingQueue<Runnable> workQueue) {
this.corePollSize = corePollSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
}
public ThreadPoolExecutor(int corePollSize, int maximumPoolSize, long keepAliveTime, boolean allowCoreThreadTimeOut, BlockingQueue<Runnable> workQueue) {
this.corePollSize = corePollSize;
this.maximumPoolSize = maximumPoolSize;
this.keepAliveTime = keepAliveTime;
if (keepAliveTime>0){
allowCoreThreadTimeOut= true;
}
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
this.workQueue = workQueue;
}
/**
* 暴露接口 接收 task任务
* @param command
*/
@Override
public void execute(Runnable command) {
if (command == null){
throw new NullPointerException();
}
int c = ctl.get();
if (c < corePollSize){ //判断是不是小于核心
addWorker(command,true); //把任务添加到核心容量
}else if (workQueue.offer(command)){ //如果核心满了 添加到队列中 成功true 失败flash
addWorker(null,false); //传空
}else {
reject(command); //如果队列也满了 使用拒绝策略
}
}
//添加任务内容
private void addWorker(Runnable task,boolean core) {
if(core){//如果true,表示使用核心容量,计数加1
ctl.incrementAndGet();
}
Worker worker = new Worker(task);//传入task任务
worker.thread.start();//调run方法
}
//拒绝策略 方法
private void reject(Runnable command) {
RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler();
rejectedExecutionHandler.rejectedExecution(command);
}
/**
* 工作内容 内部类
*/
class Worker extends ReentrantLock implements Runnable{
private Runnable firstTask;
private Thread thread;
//初始任务
public Worker(Runnable firstTask) {
this.firstTask = firstTask;
thread = new Thread(this);
}
@Override
public void run() {
runWork(this);//调用具体的执行
}
//具体的执行任务方法
private void runWork(Worker w) {
//上锁
try {
w.lock();
Runnable task = w.firstTask;
//判断task 如果不为空,或者去队列取task 不为空
if (task!=null || (task=getTask())!= null){
task.run(); //执行run方法
}
}finally {
processWorkerExit(w); //执行完重复使用
w.unlock();
}
}
//往worker传null 达到重复使用效果
private void processWorkerExit(Worker w){
addWorker(null,false);
}
private Runnable getTask() {
try {
if (workQueue.isEmpty()){
return null;
}
//三目表达式 如果开启了超时 ?传入超时时间获取队列如果是超时了返回null ? 否则直接返回队列元素
Runnable r = allowCoreThreadTimeOut ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS): workQueue.take();
if (r != null){
return r;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
/**
* 拒绝策略 内部类
*/
class RejectedExecutionHandler{
public void rejectedExecution(Runnable command){
throw new RejectedExecutionException("这个task"+command+"被拒绝");
}
}
}
試験方法
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0,5,new LinkedBlockingDeque<>());
for (int i=0;i<10;i++){
threadPoolExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println("MyThreadPoolExecutor");
}
});
}
}
}