スレッドプールとは何ですか
スレッドプールは、1つ以上のスレッドで複数のアプリケーションロジックを使用するスレッドのコレクションです。
一般的に、スレッドプールには次の部分があります。
メインタスクを完了する1つ以上のスレッド。
管理管理に使用される管理スレッド。
タスクキューを実行する必要がありました。
スレッドプールの機能:
スレッドプールの機能は、システムで実行されるスレッドの数を制限することです。
システム環境に応じて、スレッドの数を自動的にまたは手動で設定して、最適な操作効果を実現できます。システムリソースが無駄になり、システムの混雑が増加しています。スレッドプールを使用してスレッドの数を制御すると、他のスレッドが並んで待っています。タスクが実行された後、最初のタスクはキューから実行されて実行を開始します。キューに待機プロセスがない場合、スレッドプールのこのリソースが待機しています。新しいタスクを実行する必要がある場合、スレッドプールに待機ワーカーのスレッドがある場合、実行を開始できます。それ以外の場合は、待機キューに入ります。
自分でスレッドプールを実装します
上記のスレッドプールの理解に基づいて、独自のシンプルなスレッドプールを書きます。
シンプルなスレッドプールインターフェイス:
public interface threadpool <job extends runnable> {//タスク(ジョブ)を実行すると、このジョブは実行可能なvoid execute(job)を実装する必要があります。 //スレッドプールを閉じますvoid shutdown(); //ワーカースレッド、つまり、タスクを実行するために使用されるスレッドを増やしますaddworkers(int num); //ワーカースレッドを削減void removeWorker(int num); //実行されるのを待っているタスクの数を取得void getJobsize();}クライアントは、実行のために実行(ジョブ)メソッドを介してジョブをスレッドプールに送信できます。クライアントは、ジョブが実行されるのをまったく待つ必要はありません。 Execute(Job)メソッドに加えて、スレッドプールインターフェイスは、ワーカースレッドとスレッドプールを閉じる方法を提供します。各クライアントは、作業キューに入り、ワーカースレッドが処理されるのを待つジョブを提出します。
スレッドプールインターフェイスのデフォルトの実装
パブリッククラスDefaultThreadPool <job extends runnable>を実装するthreadpool <job> {//スレッドプールメンテナンスワーカースレッドの最大スレッド数プライベート静的int max_worker_numbers = 10; //スレッドプールメンテナンスワーカーのデフォルト値プライベート静的int default_worker_numbers = 5; //スレッドプールメンテナンスワーカーの最小数プライベート静的int min_worker_numbers = 1; //ワークリストを維持します。これにより、クライアントが開始したワークプライベートファイナルLinkedList <jobs = new linkedlist <job>()を追加します。 //ワーカースレッドのリストプライベート最終リスト<Worker> workers = collections.synchronizedList(new ArrayList <Worker>()); //ワーカースレッドの数private int workernum; // private atomiclong threadnum = new Atomiclong()を生成します。 //スレッドプールを生成public defaultthreadpool(){this.workernum = default_worker_numbers; InitialWorkers(this.workernum); } public DefaultThreadPool(int num){if(num> max_worker_numbers){this.workernum = default_worker_numbers; } else {this.workernum = num; }初期化職人(this.workernum); } //各ワーカースレッドプライベートvoid initialworkers(int num){for(int i = 0; i <num; i ++){worker worker = new Worker(); //労働者のスレッドワーカー(労働者)のリストに追加します。 //ワーカースレッドスレッドを起動するスレッド= newスレッド(ワーカー); thread.start(); }} public void execute(job job){if(job!= null){//スレッドの「待機/通知メカニズム」によると、ジョブ同期(job)をロックする必要があります{jobs.addlast(job); jobs.notify(); }}} //各ワーカースレッドを閉じるためのスレッドプールを閉じますpublic void shutdown(){for(worker w:workers){w.shutdown(); }}} //ワーカースレッドを追加するpublic void addworkers(int num){//ロックを追加して、次のスレッドが増加し続ける間にスレッドが増加または完了するのを防ぎ、ワーカースレッドが同期(ジョブ)を超える(num + this.workernum> max_worker_numbers){max_worker_numbers -max_worker_worker_numbers -max_worker_worker_numbers; } initializewers(num); this.workernum += num; }} //ワーカースレッドを削減するpublic void removewer(int num){synchronized(jobs){if(num> = this.workernum){throw new IllegalargumentException( "既存のスレッドの数を超える"); } for(int i = 0; i <num; i ++){worker worker = workers.get(i); if(worker!= null){//スレッドを閉じてworker.shutdown()を削除します。 workers.remove(i); }} this.workernum- = num; }} public int getJobsize(){// todo auto-enerated method stub return workers.size(); } //ワーカースレッドクラスワーカーを定義します。runnable {//ワーカーのプライベート揮発性ブールンrunning = trueかどうかを示します。 public void run(){while(running){job job = null; //待機/通知メカニズム同期(jobs){if(jobs.isempty()){try {jobs.wait(); //スレッドウェイアップ} catch(arternedexception e){//スレッドで外部割り込み操作を感知し、thread.currentthread()。戻る; }} //ジョブを取り出すjob = jobs.removefirst(); } // jobを実行するif(job!= null){job.run(); }}} //スレッドを終了しますpublic void shutdown(){running = false; }}}
スレッドプールの実装から、クライアントが実行(ジョブ)メソッドを呼び出すと、タスクリストジョブにジョブを絶えず追加し、各ワーカースレッドがジョブからジョブを読み取って実行しないことがわかります。ジョブが空の場合、ワーカースレッドが待機状態に入ります。
ジョブを追加した後、notify()メソッドが作業キュージョブに呼び出され、ワーカースレッドを起動します。ここでは、待機中のキュー内のすべてのスレッドをブロッキングキューに移動することでリソースを無駄にしないようにNotifyAll()に電話しません。
スレッドプールの本質は、スレッドセーフワークキューを使用して、ワーカースレッドとクライアントスレッドを接続することです。クライアントスレッドは、タスクをワークキューに入れた後に戻りますが、ワーカースレッドは作業キューから作業を誤って取得して実行します。作業キューが空の場合、ワーカースレッドが待機状態に入ります。クライアントがタスクを送信すると、任意のワーカースレッドを通過します。多数のタスクが提出されると、より多くのワーカースレッドが目覚めます。
参照:「Javaの同時プログラミングの芸術」Fang Tengfei