スレッドプールの理解:
coresize 3
MAXSIZE 5
blockLinkedQuenue 3
タスクは、提出された場合、<= 3、3つのスレッドの仕事を作成します
3より大きい、コアスレッドがそのタスクの実行キュースレッドを実行する自由意志を持っているキューのブロッキングを、参加するタスクは、実際に多重化が実行され実行されています
後者は、多くのタスクを提出した場合は、タスクが+は、できないことは、仕事をするスレッドの>キューの最大数より大きいされている場合、キューが先に行くと、それらを実行するための新しいスレッドを作成し、適合しない、とだけゴミを投げ、崩壊しました異常な
スレッドプールの最初に、合理的な配分
CPU -intensive
タスクが障害なく、多くの計算を必要とするCPUを集中的手段は、CPUがフルスピードで動作します。
CPUに負荷をかけ真のマルチコアCPU上の(複数のスレッドによる)を加速させるだけで可能性が高いタスク、およびシングルコアのCPU、マルチスレッドあなたは、いくつかのシミュレーションを開くかどうか、タスクが総CPU動作のため、加速することができませんこれらの能力。
IO -intensive
IO集約型、タスクはIOの多くを必要とされ、それは混雑がたくさんあります。シングルスレッドで実行されているIO集約型のタスクが待っているに無駄なCPUパワーの多くを無駄につながります。だから、大幅にリアルタイムシングルコアCPUで、実行を加速することができ、マルチスレッドプログラムでIO集約型のタスクを使用して、この加速度は主に浪費されてブロッキング時間の使用です。
そして、スレッドプールにスレッドプールのサイズを設定する方法を、左の尾を探ります。
スレッドプールサイズの合理的な配分に、最初のタスクの特性を分析しなければならない、それは次のような視点から分析することができます。
1. タスクの性質: CPU集約型のタスク、IO集約型のタスク、ハイブリッドミッション。
2. タスクの優先度:高、中、低。
3. タスクの実行時間:ロング、セミロング、ショート。
4. 依存タスク:かどうか他のシステムリソースに依存して、このようなデータベースへのアクセスなど。
タスクの性質は、実行するスレッドプールの異なるサイズの異なる場合があります。
タスクの異なる性質のために、される CPU集約型のタスクは、このようなCPU +1の数を設定するには、スレッドの数として、小型のスレッドとして設定する必要があり、IO集約型のタスクがCPUを占有していないIO操作と同じくらい多くのスレッドを使用して設定する必要があり、 CPUは引退してみましょうと座って、あなたが分割することができれば、そのようなCPU構成1のように、スレッドの数に二重の数を増やす必要があり、およびハイブリッドミッションのために、IO集約型とCPU集中処理に分け、それぞれ、その2を提供しないでください。時間のランニングは、処理時間が大きな違いであるならば、それを分割する必要はないが、ほぼ同じです。
このようなデータベース接続の結果に依存タスクなど、他のシステムリソースに依存関係が、返されたタスクは、この時間は待機時間長い、している場合は CPUが時間の長いアイドル期間で、その後、スレッドの数が多いほど、より良いするために設定する必要がありますCPUを使用しました。
もちろん、具体的かつ合理的な値スレッドプールのサイズは、試行の比較的多く、以前の法律の単なる要約以上のものを得るために、システムの実際の状況の組み合わせを必要とします。
スレッドの最適数 =((スレッド、スレッドCPU時間の待ち時間+)/スレッドCPU)、CPUの数*
このような平均値として各スレッド /((0.5 + 1.5):上記式に基づいて求め、次に推定、CPU時間は0.5秒であり、スレッドは、1.5秒に(例えばIOなどの非CPU時間)の時間を待って、CPUコアは8であります0.5)* 8 = 32。この式は、さらにに変換されます。
スレッドの最適数 =(スレッド待機スレッドCPU時間比率+ 1)CPUの数*
結論を引き出すことができます: スレッドがより高い割合を待って、より多くの必要性はスレッドします。スレッドの CPU時間の割合が高く、あまり必要性糸。 前式より、基本的にスレッドを設定するCPUとIO集中型タスクの数。
各スレッドがでタスクを実行できるようにCPU集約型のタスクは、小さなスレッドの数、そしておそらくかなりの数のCPUコアのマシンを構成するとき
IO集約型は、スレッドのほとんどがブロックされているとき、彼らは、2 * CPU監査マルチスレッド数を設定する必要があります
オペレーティングシステム名説明:
他の人が待っている間、いくつかの進歩は、コンピュータ上のほとんどの時間を費やしてきた I / Oは、ほとんどの時間を費やした上で
前者は計算集約と呼ばれている( CPU集約型)コンピュータが結合した、I / Oを集中的に呼び出され、I / Oバウンド。
待つ:
1)スレッドが待機中に()状態であるとき、それは、その前にリリースされる保有オブジェクトのモニターを待っている()メソッドは、通知スレッドが再びアクティブになっているので、オブジェクトのモニターをつかむ行く、スレッドを覚ますことができます。
待機状態にある複数のスレッド(2)の場合、コール通知する()メソッドは、ランダムなスレッドを覚ますことができます。
(3)同時に、唯一の1つのスレッドの実行が完了した後、その後、プリエンプト他のスレッドで使用するためにそれを解放する、オブジェクトのモニターを取得することができます。
呼び出し可能
では Javaの、2つの方法がありますスレッドを作成、1は、Threadクラスの継承があり、一つは、Runnableインタフェースを実現することです。しかしながら、これらの2つの方法の欠点は、実行タスクのスレッドの終了時に、結果が得られないことがあります。私たちは、一般的にのみ共有変数または共有メモリを使用すると、スレッド間通信は、タスクの結果を得る目的を達成することを意味します。しかし、 Javaは、だけでなく、タスクの結果へのアクセスを達成するために呼び出し可能と将来の事業の使用を提供します。結果を得るために、実行結果を生成し、未来への呼び出し可能タスク。
以下のように、呼び出し可能インターフェースは、Runnableインタフェースに似ていているソースコードを表示するには、定義された呼び出し可能インターフェースを見ることができます:
@FunctionalInterface パブリック インターフェース 呼び出し可能<V> { / ** *は、結果を計算し、またはそうすることができない場合に例外をスローします。 * * @return 計算結果 * @throws 結果を計算することができない場合に例外を * / Vコールは()スロー 例外。 } |
見ることができ、、Runnableインタフェースは、一般的なメソッド呼び出しの戻り値Vと、その中で異なり
今後の一般的な方法
VのGETは():何の結果が利用できない場合は、非同期計算が完了するまで、このメソッドはブロックされます、非同期実行の結果を取得します。
Vの(長いタイムアウトが、TimeUnitでユニット)GET :ブロッキング時間が設定超える場合、非同期実行結果を取得しない結果が利用可能でない場合、このメソッドはブロックしますが、時間制限があり、タイムアウト時間は、方法は、例外をスローします。
ブールisDone():タスクの実行が終了した場合、終了または正常または異常時にキャンセルのいずれか、返す真。
ブールisCanceller():タスクが完了した場合、前者が解除され、それが返されます真。
ブール(ブールmayInterruptRunning)をキャンセル:タスクが開始されていない場合は、実行キャンセル(...)メソッドはfalseを返し、タスクがすでに開始されている場合、実行はキャンセルこのタスクを実行する(true)メソッドは、タスクを停止しようとするスレッドを中断します、あなたが成功した停止した場合、trueを返す;タスクが完了したとき、実行はキャンセル、タスクが開始されたとき、キャンセル実行(偽)メソッドは、タスク実行中のスレッド(完了までの通常の実行にスレッド)、その後、falseを返すには影響しません(...)メソッドはfalseを返します。パラメータをmayInterruptRunningは実行スレッドを中断するかどうかを示します。
また、分析の方法は、実際にであることを知っている(1)タスクの実行を中断すること(2)タスク完了は、(3)タスクの実行結果の完全な量を取得し実行するかどうかを判断するために:未来は3つの機能を提供します。
私たちは、簡単な例を用い感謝タスクの結果を得るために呼び出し可能と将来の使用を。
パブリック クラス いるTestMain { パブリック 静的 ボイド メイン(文字列[]引数)がスロー InterruptedExceptionある、ExecutionExceptionを{ ExecutorServiceのエグゼキュータ=エグゼキュータ。newCachedThreadPool(); 将来の<整数>未来= executor.submit(新 AddNumberTask()); 。システムOUTの .println(スレッド。currentThread().getName()+ " スレッドは、他のタスクを実行します"); 整数整数= future.get()。 システム。アウト .println(整数)。 // スレッドプールを閉じます もし (エグゼキュータ!= nullの) executor.shutdown(); }
}
クラス AddNumberTaskが実装 呼び出し可能<整数> {
パブリック AddNumberTask(){
}
@オーバーライド 公共の 整数コールは()スロー 例外{ システム。アウト .println( "#### AddNumberTask ###コール()"); 糸。スリープ(5000); リターン 5000; }
} |
今後のモード
Future模式的核心在于:去除了主函数的等待时间,并使得原本需要等待的时间段可以用于处理其他业务逻辑
Futrure模式:对于多线程,如果线程A要等待线程B的结果,那么线程A没必要等待B,直到B有结果,可以先拿到一个未来的Future,等B有结果是再取真实的结果。
在多线程中经常举的一个例子就是:网络图片的下载,刚开始是通过模糊的图片来代替最后的图片,等下载图片的线程下载完图片后在替换。而在这个过程中可以做一些其他的事情。
首先客户端向服务器请求RealSubject,但是这个资源的创建是非常耗时的,怎么办呢?这种情况下,首先返回Client一个FutureSubject,以满足客户端的需求,于此同时呢,Future会通过另外一个Thread 去构造一个真正的资源,资源准备完毕之后,在给future一个通知。如果客户端急于获取这个真正的资源,那么就会阻塞客户端的其他所有线程,等待资源准备完毕。
公共数据接口,FutureData和RealData都要实现。
public interface Data { public abstract String getRequest(); } |
FutureData,当有线程想要获取RealData的时候,程序会被阻塞。等到RealData被注入才会使用getReal()方法。
public class FurureData implements Data {
public volatile static boolean ISFLAG = false; private RealData realData;
public synchronized void setRealData(RealData realData) { // 如果已经获取到结果,直接返回 if (ISFLAG) { return; } // 如果没有获取到数据,传递真是对象 this.realData = realData; ISFLAG = true; // 进行通知 notify(); }
@Override public synchronized String getRequest() { while (!ISFLAG) { try { wait(); } catch (Exception e) {
} } // 获取到数据,直接返回 return realData.getRequest(); }
} |
真实数据RealData
public class RealData implements Data { private String result;
public RealData(String data) { System.out.println("正在使用data:" + data + "网络请求数据,耗时操作需要等待."); try { Thread.sleep(3000); } catch (Exception e) {
} System.out.println("操作完毕,获取结果..."); result = "余胜军"; }
@Override public String getRequest() { return result; }
|
FutureClient 客户端
public class FutureClient {
public Data request(String queryStr) { FurureData furureData = new FurureData(); new Thread(new Runnable() {
@Override public void run() { RealData realData = new RealData(queryStr); furureData.setRealData(realData); } }).start(); return furureData;
}
} |
调用者:
public class Main {
public static void main(String[] args) { FutureClient futureClient = new FutureClient(); Data request = futureClient.request("请求参数."); System.out.println("请求发送成功!"); System.out.println("执行其他任务..."); String result = request.getRequest(); System.out.println("获取到结果..." + result); }
} |
调用者请求资源,client.request("name"); 完成对数据的准备
当要获取资源的时候,data.getResult() ,如果资源没有准备好isReady = false;那么就会阻塞该线程。直到资源获取然后该线程被唤醒。