並行プログラミング用のエグゼキュータスレッドプール

1.スレッドプールの概要

1.1スレッドプール:
「スレッドプール」は、その名前が示すように、スレッドキャッシュです。スレッドは希少なリソースです。制限なしで作成すると、システムリソースを消費するだけでなく、システムの安定性も低下します。したがって、Javaスレッド用のスレッドプールを提供します。統合された割り当て、調整、および監視
。1.2スレッドプールの概要
Web開発では、サーバーは要求を受け入れて処理する必要があるため、要求を処理するためにスレッドが割り当てられます。リクエストごとに新しいスレッドを作成する場合、実装は非常に簡単ですが、問題があります。同時リクエストの数が非常に多いが、各スレッドの実行時間が非常に短い場合、スレッドが作成され、頻繁に破壊されます。システムの効率が大幅に低下します。サーバーは、実際のユーザーリクエストを処理するよりも、リクエストごとに新しいスレッドの作成とスレッドの破棄に多くの時間とシステムリソースを費やしているように見える場合があります。それで、破壊されることなくタスクを実行する方法はありますが、他のタスクを実行し続けることができますか?これがスレッドプールの目的です。スレッドプールは、スレッドライフサイクルのオーバーヘッドとリソース不足の問題に対するソリューションを提供します。複数のタスクにスレッドを再利用することにより、スレッド作成のオーバーヘッドは複数のタスクにわたって償却されます。
1.3スレッドプールを使用するのはいつですか?

  • 単一タスクの処理時間は比較的短い
  • 処理する必要のあるタスクの数が多い
    1.4スレッドプールの利点
  • 既存のスレッドを再利用し、スレッドの作成と終了のオーバーヘッドを減らし、パフォーマンスを向上させます
  • 応答速度を向上させます。タスクが到着すると、スレッドが作成されるまで待たずにタスクをすぐに実行できます。
  • スレッドの管理性を向上させます。スレッドは希少なリソースです。無制限に作成すると、システムリソースを消費するだけでなく、システムの安定性も低下します。スレッドプールは、均一な割り当て、調整、および監視に使用できます。

2.エグゼキュータフレームワーク

実行者クラス図
Executorインターフェースは、スレッドプールフレームワークの最も基本的な部分であり、Runnableを実行するためのexecuteメソッドを定義します
。ExecutorServiceは一般的なサブインターフェースであり、重要なメソッドが定義されています。

public interface ExecutorService extends Executor {
    
    

    //在完成已提交的任务后封闭办事,不再接管新任务
    void shutdown();

    //停止所有正在履行的任务并封闭办事
    List<Runnable> shutdownNow();

	//测试是否该ExecutorService已被关闭
    boolean isShutdown();
	//测试是否所有任务都履行完毕了
    boolean isTerminated();

    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;

	//可用来提交Callable或Runnable任务,并返回代表此任务的Future对象
    <T> Future<T> submit(Callable<T> task);
    <T> Future<T> submit(Runnable task, T result);
    Future<?> submit(Runnable task);


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
        throws InterruptedException;


    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks)
        throws InterruptedException, ExecutionException;

    <T> T invokeAny(Collection<? extends Callable<T>> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

2.1スレッドプールには5つの状態があります

RUNNING    = ­1 << COUNT_BITS; //高3位为111
SHUTDOWN   =  0 << COUNT_BITS; //高3位为000
STOP       =  1 << COUNT_BITS; //高3位为001
TIDYING    =  2 << COUNT_BITS; //高3位为010
TERMINATED =  3 << COUNT_BITS; //高3位为011

1、ランニング

  1. 状態の説明:スレッドプールがRUNNING状態の場合、新しいタスクを受け取り、追加されたタスクを処理できます。
  2. 状態の切り替え:スレッドプールの初期化状態はRUNNINGです。つまり、スレッドプールが作成されると、それはRUNNING状態になり、スレッドプール内のタスクの数は0になります。
    2.シャットダウン
  3. 状態の説明:スレッドプールがSHUTDOWN状態の場合、新しいタスクを受信しませんが、追加されたタスクを処理できます。
  4. 状態の切り替え:スレッドプールのshutdown()インターフェースが呼び出されると、スレッドプールはRUNNING-> SHUTDOWNから変更されます。
    3.停止
  5. 状態の説明:スレッドプールがSTOP状態の場合、スレッドプールは新しいタスクを受信せず、追加されたタスクを処理せず、処理中のタスクを中断します。
  6. 状態の切り替え:スレッドプールのshutdownNow()インターフェイスが呼び出されると、スレッドプールは(RUNNINGまたはSHUTDOWN)-> STOPから変更されます。
    4.片付け
  7. ステータスの説明:すべてのタスクが終了し、ctlによって記録された「タスクの数」が0の場合、スレッドプールはTIDYINGになります。スレッドプールがTIDYINGになると、フック関数terminate()が実行されます。ThreadPoolExecutorクラスのterminate()は空です。スレッドプールがTIDYINGになったときにユーザーが対応する処理を実行したい場合は、terminate()関数をオーバーロードすることで実現できます。
  8. 状態の切り替え:スレッドプールがSHUTDOWN状態にあり、ブロッキングキューが空であり、スレッドプールで実行されるタスクも空の場合、SHUTDOWN-> TIDYINGになります。スレッドプールがSTOP状態のとき、スレッドプールで実行されたタスクが空のときは、STOP-> TIDYINGになります。
    5.終了しました
  9. 状態の説明:スレッドプールは完全に終了し、TERMINATED状態になります。
  10. 状態の切り替え:スレッドプールがTIDYING状態の場合、terminate()の実行後、TIDYING-> TERMINATEDになります。
    TERMINATEDに入る条件は次のとおりです。
  • スレッドプールはRUNNING状態ではありません。
  • スレッドプールの状態は、TIDYING状態でもTERMINATED状態でもありません。
  • スレッドプールのステータスがSHUTDOWNで、workerQueueが空の場合。
  • workerCountは0です。
  • TIDYINGステータスを正常に設定しました。

3.スレッドプールの作成:

沿って遺言執行者APIによって作成されるスレッドプールのタイプの概要:
3.1固定数のスレッドプール

    /**
    *创建重复使用固定数量线程的线程池
	*使用提供的
	*在需要时创建新线程的ThreadFactory。在任何时候,
	*最多{@code nThreads}线程将处于活动处理状态
	*任务。如果在所有线程
	*活动,它们将在队列中等待线程
	*可用。如果任何线程在
	*在关闭之前执行,如果
	*需要执行后续任务。池中的线程将
	*存在,直到显式{@ Link ExcutoService }shutdown
    * shutdown}.
	*@param nThreads 线程池中的线程数
	*@param threadFactory创建新线程时要使用的工厂
	*@return 返回新创建的线程池
	*@threadFactory为空时抛出NullPointerException
	*如果{@code nThreads<=0},则@throws IllegalArgumentException
     */
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    
    
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

3.2。並列スレッドプール
これは1.8で新しく追加されたスレッドプールであり、ForkJoin関連の操作が主に使用されていることがわかります。

    /**
     * 并行线程池
     * 作为其目标并行级别。
	 *@返回新创建的线程池
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
    
    
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

3.スレッドが1つしかないスレッドプール
実際には、スレッドが1つしかないため、これをスレッドプールと呼ぶことはできません。コアスレッド=最大スレッド= 1。これは、キュー内のタスクの順次実行を保証する必要があるシナリオに適しています。

    /**
	*创建使用单个工作线程操作的执行器
	*从无限的队列中。(但请注意,如果
	*线程在执行之前由于失败而终止
	*关闭,如果需要执行新的
	*后续任务。)保证执行任务
	*按顺序,任何时候都不会有多个任务处于活动状态
	*给定的时间。与其他等价物不同
	*{@code newFixedThreadPool(1)}返回的执行器是
	*保证不可重新配置以使用其他线程。
     *
     * @return the newly created single-threaded Executor
     */
    public static ExecutorService newSingleThreadExecutor() {
    
    
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

4.キャッシュスレッドプール
必要に応じてスレッドを作成します。コアスレッドはありません。60年代にタスクがない場合は、残っているスレッドがリサイクルされます。60年代にタスクがある場合は、既存のスレッドを再利用できます。彼のワークキューはSynchronousQueueであることに注意してください。ここでは簡単な紹介です)、各put操作はtake操作を待機する必要があります。つまり、タスクの生成速度が消費速度よりも速い場合、新しいスレッドは作成されません。 。このスレッドプールは、多数の小さなタスクが実行されるシナリオに適しています。

    /**
	*创建根据需要创建新线程的线程池,但是
	*将重用以前构造的线程
	*可用。这些池通常会提高性能
	*执行许多短期异步任务的程序。
	*对{@code execute}的调用将重用先前构造的
	*线程(如果可用)。如果没有现有线程可用,则新建
	*将创建线程并将其添加到池中。具有
	*60秒未使用被终止并从
	*缓存。因此,一个空闲时间足够长的池将
	*不消耗任何资源。请注意,与
	*属性,但有不同的详细信息(例如,超时参数)
	*可以使用{@link ThreadPoolExecutor}构造函数创建。
     * @return the newly created thread pool
     */
    public static ExecutorService newCachedThreadPool() {
    
    
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

5.遅延スレッドプール
ScheduledThreadPoolExecutorはThreadPoolExecutorを継承するため、superは最終的にThreadPoolExecutorのコンストラクターに転送されます。スレッドの最大数はintの最大値であり、ワークキューはDelayedWorkQueueです。スレッドプールは適切です。遅延タスクを実行するため。

    /**
	*创建可以调度命令的单线程执行器
	*在给定的延迟后运行,或周期性地执行。
	*(但请注意,如果
	*线程在执行之前由于失败而终止
	*关闭,如果需要执行新的
	*后续任务。)保证执行任务
	*按顺序,任何时候都不会有多个任务处于活动状态
	*给定的时间。与其他等价物不同
	*{@code newScheduledThreadPool(1)}返回的执行器是
	*保证不可重新配置以使用其他线程。
	*@返回新创建的计划执行器
     */
    public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
    
    
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }
        public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    
    
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1, threadFactory));
    }

おすすめ

転載: blog.csdn.net/qq_38130094/article/details/104165504