転載:https://www.cnblogs.com/trust-freedom/p/6681948.html
ここでのThreadPoolExecutor#execute(Runnable command)
は、スレッドプールで実行できるケースのみを分析します。コマンドはThreadPoolExecutor#Workerオブジェクトにパッケージ化されます
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
ワーカーはRunnableインターフェースを実装します。上記のコンストラクターから、スレッドファクトリによって生成されたスレッドによって実行されるRunnableはコマンドではなく、コマンドのパッケージ化オブジェクトWorkerであることがわかります。(GetThreadFactory()。newThread(this))
したがって、スレッドの実行時にワーカーオブジェクトのrunメソッドが実行されます。
ワーカー#run
public void run() {
runWorker(this);
}
runWorkerメソッドの簡略化されたバージョン。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
while (task != null || (task = getTask()) != null) {
task.run();
}
}
タスクは最初はコマンドであり、最後の実行はコマンドのrunメソッドであることがわかります。実行前にw.firstTaskはnullに設定されるため、whileループが繰り返されると、前の条件は確立されません。次に、2番目の条件getTaskを見てください
getTaskメソッドの簡略化されたバージョン。
private Runnable getTask() {
for (;;) {
int c = ctl.get();
int wc = workerCountOf(c);
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
}
}
ここでは、コアスレッドの有効期限は考慮されていません。したがって、timedの意味は、ワーカースレッドがコアスレッドよりも大きいかどうかです。そうである場合、キューヘッダーデータはタイムアウト期間を指定することによって取得されます(コアスレッド番号よりも大きいスレッドを表すため、データがない場合キュー内で、コアスレッド番号よりも大きいスレッドが一定期間内に存在します。時間の経過後に破棄されます)。それ以外の場合は、takeを使用して反対の列のヘッダーデータを取得します。列が空の場合、takeメソッドは常にブロックされます(Noはコアスレッドを意味しないため、キューにデータがない場合、コアスレッドはブロックされます)。
これは、runWorkerとgetTaskの2つのメソッドからわかります。
- スレッドプールがブロックされる理由は、コアスレッドが空のキューでブロックされるため、shutDownが必要ですが、スレッドプールがタスクを実行していない場合、つまりコアスレッドがない場合、shutDownは必要ありません。(これには、タスクを実行せずにコアスレッドを事前に開始できるスレッドプールは含まれません)
- 最初にスレッドプールに追加されたコアスレッドは、必ずしもコアスレッドであるとは限りません。これは、スレッドが現在のタスクの実行を終了した後、現在のワーカースレッドがコアスレッドよりも大きいかどうかに基づいています。
- 非コアスレッドの存続時間は、現在のタスクが実行された後、スレッドが空のキューでブロックするタイムアウト期間です。