高度なマルチスレッドのJavaのスレッドプールで10086顧客サービスホットラインの理解


 ニーチェは、人間が経験していないのか理解できないと言いました。多くの概念を理解し、覚えておくことを強制することはできませんので、あなたが実際の生活の中でケースを結合する必要があります。

ホットラインケース

 スレッドプールは、顧客サービスコールのビジネスを実行するためにユーザーに例えることができます理解するために、顧客サービス事業者は、残りの500人を想定して、既存の500人のユーザーは、顧客との一対一あり、その後、スポンジで最初の501人のユーザーが聞こえます声が待っている:スポンジボブは唯一、待つことができ、500人の以上のユーザーがハングアップしている場合、スポンジボブが正常に生きている人間に接続することができます。「もしもし、今忙しい...休む!」
 ユーザーの電話を顧客サービスへのすべてのために作業であり、そして各顧客はというし、全体の顧客サービスの背景は50,000タスクを完了するように一日あたり100回のコールへの顧客のアクセスなど、わずか500タスク、より多くのタスクを完了することができます。

ここに画像を挿入説明

アナロジー:顧客サービスは、バックグラウンドスレッド・プールとして見ることができ、500の顧客サービスは、500人のユーザーがタスクである、と電話がこの事を実行するためにオンになり、500件のスレッドとして見られたスレッドであることができ、最初のユーザー501コールの顧客サービスホットラインはかなり501タスクでは、より多くの最大スレッドより最大キューが、彼らは開始前に完了するために、別のスレッドになるまで待たなければならないことができます。これは、スレッドの再利用を可能にします。

このアナロジー実際の例は、以下のような問題点を見つけることができます。

  • スレッドには、貴重なメモリリソース、1MBのスペースを占めてシングルスレッドです。簡単に過剰に割り当てるメモリのオーバーフローにつながります。
  • 頻繁に作成および破棄のスレッドがパフォーマンス低下のプログラムで、その結果、オーバーヘッド仮想マシンの復旧周波数資源を増加します

スレッドプールの導入

1.スレッドの概念

以下は、Baiduの百科事典からの抜粋です。

 スレッドプールは、タスクを処理するマルチスレッド処理のフォームをキューに追加して、スレッドが作成されたときに自動的にこれらの作業を開始されますです。スレッドプールのスレッドは、バックグラウンドスレッドです。各スレッドは、デフォルトの優先順位実行するデフォルトのスタックサイズを使用し、マルチスレッド単位です。マネージコード内のスレッドがアイドル状態である場合(例えばイベントを待っている)、その後、忙しくして他のすべての補助プロセッサにスレッドプールのスレッドを挿入します。すべてのスレッドプールのスレッドが常に忙しいですが、キューは保留中の作業が含まれている場合は、スレッドプールは、一定期間後に別のワーカースレッドを作成しますが、スレッドの数は、最大値を超えることはありません。より多くの最大スレッドよりは、キューに入れることができますが、彼らは別のスレッドが開始する前に完了するまで待たなければなりません。

2.スレッドプールの役割:

  • タスクは、スレッドプールに提出されます。スレッドプールのスレッドによって割り当てられたタスクを実行し、現在のタスクの終了後にスレッドを再利用します。
  • コンテナのスレッド。割り当てられたスレッドの数を制限するように設定することができます。
  • プールに、両方のスレッドプールスレッドオブジェクトで予め作成されたスレッドのオブジェクト。
  • 頻繁に作成および破棄スレッドを避けてください。

スレッドプールの取得

1.一般的なスレッドプールのクラスおよびインタフェース

  • エグゼキュータ:トップレベルのインタフェースのスレッドプール
方法 説明
ボイド(Runnableをコマンド)を実行します 一部の将来の時に与えられたコマンドを実行します。
  • ExecutorServiceの:
     スレッドプールエグゼキュータ継承インターフェース、および増加し、いくつかの親インターフェイスの動作を最適化、タスクコードを提出する(Runnableをタスク)によって提出されてもよいです。
方法 説明
将来は(呼び出し可能タスク)を提出します 値は、タスクに代わって、実行し、将来の保留中の結果を返すようにタスクを提出返さ。
フューチャー<?>提出(Runnableをタスク) 実行可能なタスクを送信することは行われ、そのミッションの未来を言って返されました。
将来の提出(Runnableをタスク、T結果) 提出された実行可能なタスクではなく、リターン、そのタスクを実行します
  • 執行ファクトリクラス:

 これは、以下の方法により、スレッドプールのスレッドの固定数を得ることができます。あるスレッドプールのスレッドパラメータの数

方法 説明
静的ExecutorServiceのnewFixedThreadPool(int型にnthreads) スレッドプール、共有アンバウンド形式のキューからの実行の固定数を再利用するスレッドプールのスレッドを作成します。

道の作成

//线程池引用 ===> Executors工具类创建线程
        ExecutorService executorService = Executors.newFixedThreadPool(2);

 その後、自動的に新しい、上限を作成しない場合にも、newCachedThreadPool()は、動的スレッドプールの数を取得することができます。

JAVAAPI:

必要に応じて新しいスレッドを作成するスレッドプールを作成しますが、使用可能な場合は、事前に構築されたスレッドを再利用します。これらのプールは、典型的には、プログラムの多くの短命非同期タスクの実行を改善します。(利用可能な場合)以前に構築スレッドを再利用します実行するために呼び出します。ノースレッド場合は、新しいスレッドが作成され、プールに追加します。ない60秒のスレッドが終了すると、キャッシュから削除されます使用します。そのため、プールはすべてのリソースを消費しない長い間アイドル状態のままになります。ノートでは、しかし、あなたは、プールThreadPoolExecutorコンストラクタを使用して、類似した特性を有する異なる内容の(例えば、タイムアウトパラメータ)を作成することができますしてください。

方法 説明
静的ExecutorServiceのnewCachedThreadPool() 必要に応じて新しいスレッドを作成するスレッドプールを作成しますが、使用可能な場合は、事前に構築されたスレッドを再利用します。

2.コードケース

 現在のタスクは、Runnableを、印刷サイクルを5回実施、クロススレッドプールがあるexecutorServiceタスクを実行するためには、それぞれ、スレッドプール内のスレッドの最大数は2です。

public class TestThreadPool {
    public static void main(String[] args){

        //线程池引用 =  Executors工具类创建线程
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        Runnable runnable = new MyTask();
        executorService.submit(runnable);
    }
}
class MyTask implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i <5; i++) {
            System.out.println(Thread.currentThread().getName()+" MyTask: "+i);
        }
    }
}

結果を印刷します:
ここに画像を挿入説明
タスクを複数回送信された場合?例えば、タスクは、スレッドプールスレッドプールのスレッドが上限よりも大きい場合に、あなたがします提示
起こる多重スレッド?
試験方法:

//线程池引用 =  Executors工具类创建线程
 ExecutorService executorService = Executors.newFixedThreadPool(2);
 Runnable runnable = new MyTask();
 executorService.submit(runnable);
 executorService.submit(runnable);
 executorService.submit(runnable);

 どうやら多重化される3つのタスクは、そのため、スレッドが存在しなければならない提出している2件のスレッドがあります。

結果を印刷:
ここに画像を挿入説明
 印刷結果から、スレッド1は、最適化の目的を達成するために、頻繁にスレッドの作成と破壊を回避するために、二回多重化されています。

呼び出し可能インターフェース

1.概念の説明

 以上説明したExecutor時間、リストは、最初のパラメータは、以下の3つの方法、方法でありますCallable

方法 説明
将来は(呼び出し可能タスク)を提出します 値は、タスクに代わって、実行し、将来の保留中の結果を返すようにタスクを提出返さ。
フューチャー<?>提出(Runnableをタスク) 実行可能なタスクを送信することは行われ、そのミッションの未来を言って返されました。
将来の提出(Runnableをタスク、T結果) 提出された実行可能なタスクではなく、リターン、そのタスクを実行します
@FunctionalInterface
public interface Callable<V>

 結果を返し、異常なタスクにつながる可能性があります。コールと呼ばれる単一のパラメータを定義しない方法によって達成。
彼らはクラスのインスタンスが別のスレッド設計によって実行することができるされているので、呼び出し可能インタフェースは、Runnableをに類似しています。しかし、AのRunnableはあなたが検討されている例外を投げることができない、結果を返しません。

2.シナリオ

 我々は計算する必要がある場合は1+2+3+......+1000000、私たちのように、それぞれ、実行するために複数のスレッドに配信する必要があることを、プロセスの結果をThread1スレッド2は、数字100,000 200,000合計を行うと10万個の数字を実行し、前に...しかし、問題はそれが含まれThread1、実行を実行の結果は返さなければならない、またはThread21の結果に応じて進行せず、明らかに、この時間のクラスが実装で使用することができないRunnableインターフェイスカバレッジrun戻りランは空隙であるため、解決する方法の。

class MyTask implements Runnable{
    @Override
    public void run() {
      //1+2+...+100000
    }
}

これは、使用してCallable結果を返すと、異常なタスクを引き起こす可能性があります。その最大の特徴があるよう。
ここに画像を挿入説明

3.メソッド

方法 説明
Vコール() 結果を計算することは、あなたがそれを行うことができない場合、それは例外がスローされます。
  • 実装は、スレッドのタスクを表す後JDK5は、Runnableインタフェースと同様、添加しました。
  • 呼び出し可能な、一般的な戻り値を持っている、あなたは例外を宣言することができます。
public interface Callable<V>{
	public V call() throw Exception;
}

前記方法の適用

public class TestCallable {
    public static void main(String[] args){
        //创建线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        Callable task = new Task();
        executorService.submit(task);
        executorService.submit(task);
        executorService.submit(task);
    }
}
class Task implements Callable<String>{
    @Override
    public String call() throws Exception {
        for (int i = 0; i <5 ; i++) {
            System.out.println(Thread.currentThread().getName()+" : "+i);
        }
        return null;
    }
}

結果を印刷します:
ここに画像を挿入説明
 明らかに3つのタスクを提出した2つのスレッドがゆえ、ある、2つの多重化を通します。

将来のインタフェース

1.はじめに

&EMSPに、私たちはケースを紹介して開始します:計算1+2+3+......+1000000我々は、それぞれ実行する複数のスレッドに提供するために必要なこのプロセスの結果を、呼び出し可能な型を返すことができますが、どのようにリターンのさまざまなスレッドの合計は、それを入力しますか?ここで紹介する将来のインターフェースの必要性、カプセル化するオブジェクトcall()戻り値を

JAVAAPI:

A今後の計算結果。計算をチェックする方法は、その完了を待って、完了し、結果を取得します。必要に応じて計算方法が準備されるまで、ブロックを検索取得した後の結果のみを使用することができます。キャンセルの方法で行っキャンセル。タスクが正常に完了またはキャンセルされたかどうかを判断する別の方法を提供します。計算が完了した後、計算を取り消すことができません。あなたがそう取消不能の形で、将来を使いたいのですが、使用可能な結果を​​提供していない場合は、タスクの結果を基礎として、今後の<?>型テーブルとリターンのヌルを宣言することができます。

2.方法

方法 説明
ブールキャンセル(ブールmayInterruptIfRunning) このタスクの実行の取り消しを試みます。
VのGET() 待機計算が完了し、その後、結果を取得します。
VのGET(長いタイムアウト、TimeUnitでユニット) あなたは(利用可能な場合)、最大の計算を完了するために与えられた時間を待ち、その後、結果を取得する必要がある場合。
ブールisCancelled() それが正常に完了する前にこのタスクが取り消された場合は、trueを返します。
ブールisDone() このタスクが完了した場合はtrueを返します。

サブタスクの問題を解決する3行なわ1 + 2 + ... + 100

public class TestCallable {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		System.out.println("程序开始");
		//创建线程池
		ExecutorService es = Executors.newFixedThreadPool(3);
		
		Callable<Integer> task1 = new MyTask1();
		Callable<Integer> task2 = new MyTask2();
		//接收两个任务的返回值
		Future<Integer> f1 = es.submit(task1);
		Future<Integer> f2 = es.submit(task2);
		//检索计算结果并返回给变量
		Integer result1 = f1.get();//无限期等待
		Integer result2 = f2.get();//无限期等待
		//输出结果
		System.out.println("result1:"+result1 + " + result2:"+result2 +" = " +(result1+result2));		
	}
}
//线程1计算1+2+....+50
class MyTask1 implements Callable<Integer>{
	@Override
	public Integer call() throws Exception {
	  	Thread.sleep(5000);
		Integer sum = 0;
		for (int i = 1; i <= 50; i++) {
			sum += i;
		}
		return sum;
	}
}
//线程2计算51—+52+.....+100
class MyTask2 implements Callable<Integer>{
	@Override
	public Integer call() throws Exception {
	    Thread.sleep(5000);
		Integer sum = 0;
		for (int i = 51; i <= 100; i++) {
			sum += i;
		}
		return sum;
	}
}

(これは映画である)の結果を印刷:
ここに画像を挿入説明
 印刷結果から、V get()今後の非同期(マルチスレッド)の処理結果(待ちの形でブロックされているcall()戻り値);の人気を、ここでは5のためにスリープ状態に二つのスレッドを聞かせて二、その待機期間中に二つのスレッドの過程で、V get()待機中のスレッドの形でブロックされているが得るためにした後、終了したFuture戻り値を、


 実際には、非常に親しい友人があった - フィールは、分散
ここに画像を挿入説明

公開された85元の記事 ウォンの賞賛196 ビュー130 000 +

おすすめ

転載: blog.csdn.net/qq_44717317/article/details/104928731