Javaでスレッドプールを実装する2つの方法

01スレッドプールの適用シナリオ

(1)アプリケーション

たとえば、コレクションの現在のレタッチソフトウェア。1920 x 1080の画像には200万以上のピクセルがあり、画像全体の各ピクセルを処理するには多くの計算が必要です。

(2)サーバー側

サーバーサイドがビッグデータと多数のリクエストを処理する場合、単一のスレッドだけで実行すると、要求を満たすことができません。

また、アプリケーションやサーバーの処理に関係なく、複数のスレッドが使用されている場合でも、スレッドが頻繁に作成および破棄されると、最終的な作成および破棄時間が実際の実行時間よりも長くなる場合があります。オブジェクトの再利用は良い選択なので、スレッドプールを選択できます。

スレッドプールに含まれる一般的に使用されるJavaクラスには、ThreadPoolExecutor、Executorsなどがあります。

02 ThreadPoolExecutor

(1)ThreadPoolExecutorはオブジェクトを作成するのがより複雑です次の図は、JDK 11で提供されるいくつかのコンストラクタを示しています。

これらのパラメーターは主に、スレッドプールのいくつかの重要なパラメーターの設定に関係します。例として、ほとんどのパラメーターを持つコンストラクターを取り上げます。

public ThreadPoolExecutor(int corePoolSize, 
													int maximumPoolSize, 
													long keepAliveTime, 
													TimeUnit unit, 
													BlockingQueue<Runnable> workQueue, 
													ThreadFactory threadFactory, 
													RejectedExecutionHandler handler) {
	...
}
复制代码

corePoolSize アイドル時にスレッドプールに保存されたスレッドの数。

maximumPoolSize スレッドプールで許可されるスレッドの最大数。

keepAliveTime アイドルスレッドがあり、既存のスレッドの数がcorePoolSizeより大きい場合、スレッドは指定された時間後に削除され、指定された時間内にスレッドは削除されません。

unit keepAliveTimeの設定時間単位を参照します。

workQueue 実行前にタスクキューを保存するために使用されます。

threadFactory カスタムスレッドを作成するためのファクトリクラスを指定します。

handler RejectedExecutionHandlerの目的は、拒否されたスレッド情報の記録など、スレッドプールが閉じられた後にタスクが追加されたときに処理を実装することです。

(2)メソッドの実行()および送信()

どちらもスレッドプールのようなタスクを送信できますが、詳細は異なります。

execute()タスクを追加できますが、タイプはRunnableのみであり、タスクは結果を返すことができません。セルフスレッド例外が発生すると、例外情報が直接出力され、メインスレッドは例外情報をキャプチャできません。

submit()タスクを追加できますが、Futureオブジェクトを返し、返された結果をFutureから取得できます。例外が発生すると、例外情報をメインスレッドでキャプチャできます。

submit()メソッドのパラメーターには、2種類の呼び出し可能インターフェースとRunnableが含まれますが、主な違いは次のとおりです。

(A)Callableインターフェースのcall()メソッドは戻り値を持つことができますが、Runnableインターフェースのrun()メソッドは戻り値を持ちません。

(B)Callableインターフェースのcall()メソッドは一生例外をスローできますが、Runnableインターフェースのrun()メソッドは例外がスローされることを宣言できません。

(3)その他の一般的な方法

shutdown() メインスレッドはすぐに終了し、ブロックされません。実行されたスレッドプール内のスレッドは引き続き実行されます。新しいタスクはスレッドプールに追加されません。スレッドプールは、すべてのスレッドの実行が完了するまで実行され続けます。

スレッドがすぐにSHUTDOWN状態をプログラムする場合、現時点ではスレッドプールにタスクを追加する必要はありません。そうでない場合は、RejectedExecutionException例外をスローします。

shutdownNow()すべてのタスクを中断し、InterruptExceptionをスローします。実行直後にSTOP状態に入り、実行中のすべてのスレッドを停止しようとし、スレッドプールでまだ待機しているタスクを処理しなくなります。

このメソッドが実行されると、実行されていないタスクが返されます。

isShutdown() スレッドプールが閉じているかどうかを確認します。

isTerminating() 終了処理中の場合はtrueを返します。

isTerminated() すべてのタスクが完了したと判断します。

awaitTermination() スレッドプールが指定された時間内に作業を終了したかどうかを確認します。

03執行者

エグゼキュータは、すでに提供されているメソッドを介してスレッドプールの作成を容易にすることができるスレッドプール作成クラスです。

(1)エグゼキューターが提供する一般的な方法:

newCachedThreadPool() スレッドを自動的にリサイクルできる無制限のスレッドプールを作成します。いわゆる「最大スレッドプール」は、プールに格納されるスレッド数の理論上の最大値であり、Integer.MAX_VALUEの最大値です。

newCachedThreadPool(ThreadFactory) カスタムスレッドプール内のスレッド

newFixedThreadPool(int) 制限付きスレッドプールを作成する

newFixedThreadPool(int, ThreadFactory) カスタムスレッドの制限付きスレッドプールを作成します。

newSingleThreadExector() キューにタスクを実装するシングルスレッドプールを作成します。

newSingleThreadExecutor() ファクトリを使用してシングルスレッドプールを作成します。

04ケース

(1)ThreadPoolExecutorを使用してスレッドプールを作成する

package com.page.concurrent.pool;

import java.util.concurrent.*;

public class Game {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
        		1, 2, 1000 * 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>());

        Future<String> future = threadPoolExecutor.submit(() -> {
            System.out.println("Should work 4 seconds.");
            Thread.sleep(1000 * 4);
            System.out.println("Work done.");
            return "OK";
        });

        String result = future.get();
        System.out.println("Thread response result is " + result);
        threadPoolExecutor.shutdownNow();
        System.out.println("Thread pool status: isShutdown=" + threadPoolExecutor.isShutdown());
        Thread.sleep(1000 * 5);
        System.out.println("Thread pool status: isTerminated" + threadPoolExecutor.isTerminated());
    }
}

复制代码

(2)エグゼキューターを使用してスレッドプールを作成する

package com.page.concurrent.pool;

import java.util.concurrent.*;

public class Game {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();

        Future<String> future = executorService.submit(() -> {
            System.out.println("Should work 4 seconds.");
            Thread.sleep(1000 * 4);
            System.out.println("Work done.");
            return "OK";
        });

        String result = future.get();
        System.out.println("Thread response result is " + result);
        executorService.shutdownNow();
        System.out.println("Thread pool status: isShutdown=" + executorService.isShutdown());
        Thread.sleep(1000 * 5);
        System.out.println("Thread pool status: isTerminated" + executorService.isTerminated());
    }
}

复制代码

おすすめ

転載: juejin.im/post/5e9830c4518825738c3648c9