Javaスレッドプールの知識学習のまとめ


スレッドプールのメリット:
  • は存在するスレッドを再利用し、オブジェクトの作成、消滅のオーバーヘッドを減らし、性能が良い.
  • は最大同時スレッド数を効果的に制御し、システム資源の利用率を高めると同時に、過剰な資源競争を回避し、ブロックを回避することができる.
  • は、タイミング実行、定期実行、単一スレッド、同時数制御などの機能を提供する.

  • ThreadPoolExecutorの構築方法は次のとおりです.
        public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
            ...
        }

    構築方法のパラメータの説明:
  • corePoolSize:

  • コアスレッドの数.実行スレッド数がcorePoolSizeより小さい場合は、スレッドプールに他のスレッドが空いている場合でも、新しいスレッドを直接作成してタスクを処理します.
  • maximumPoolSize:

  • スレッドの最大スレッド数.スレッドプールの数がcorePoolSize以上でmaximumPoolSize以下の場合、ワークキューがいっぱいになった場合にのみ、タスクを処理するための新しいスレッドが作成されます.
  • keepAliveTime:

  • スレッドにタスクが実行されていない場合、最大終了時間はどのくらいですか?
  • unit:

  • keepAliveTimeの時間単位、例えばTimeUnit.SECONDS
  • workQueue:

  • キューをブロックし、実行待ちのタスクを格納することが重要です.スレッドプールの実行プロセスに大きな影響を与えます.
  • threadFactory:

  • スレッドを作成するスレッドファクトリ.
  • rejectHandler:

  • タスクの処理を拒否したときのポリシー.JDKは主に4種類の飽和戦略を提供した.
    A)直接放出異常(デフォルトポリシー)AbortPolicy
    B)呼び出し元のスレッドでタスクCallerRunsPolicyを実行する
    C)現在のタスクDiscardOldestPolicyを実行するためにキュー内で最も上位のタスクを破棄する
    D)現在のタスクDiscardPolicyを直接廃棄する
    TreadPoolExecuteインスタンスを使用する4つの基本的な方法:
  • execute():タスクをコミットし、スレッドプールに渡して実行します.
  • submit():タスクをコミットし、実行結果execute+Futureを返すことができます.
  • shutdown():スレッドプールを閉じ、タスクの実行を待つ.
  • shutdownNow():スレッドプールを閉じ、タスクの実行を待たずに実行中のスレッドを一時停止します.

  • TreadPoolExecuteを監視する方法:
  • getTaskCount():スレッドプールで実行されたタスクと実行されていないタスクの合計数.
  • getCompletedTaskCount():完了したタスクの数;
  • getPoolSize():スレッドプールの現在のスレッド数;
  • getActiveCount():現在のスレッドプールでタスクを実行しているスレッドの数.

  • Exexutorフレームワークインタフェース:
  • Executors.newCachedThreadPool

  • キャッシュ可能なスレッドプールを作成します.スレッドプールの長さが処理の必要以上の場合は、空きスレッドを柔軟に回収できます.リサイクル可能でない場合は、新しいスレッドを作成します.
            ExecutorService executorService = Executors.newCachedThreadPool();
    
            for (int i = 0; i < 10; i++) {
                final int index = i;
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        log.info("task:{}",index);
                    }
                });
            }
    
            executorService.shutdown();
  • Executors.newFixedThreadPool

  • スレッドの最大同時数を制御できる定長スレッドプールを作成し、超過したスレッドがキュー内で待機します.
            ExecutorService executorService = Executors.newFixedThreadPool(3);
    
            for (int i = 0; i < 10; i++) {
                final int index = i;
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        log.info("task:{}",index);
                    }
                });
            }
    
            executorService.shutdown();
  • Executors.newScheduledThreadPool

  • 定時的、周期的なタスク実行をサポートする定長スレッドプールを作成します.
            ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
    
            //  , 
            executorService.scheduleAtFixedRate(new Runnable() {
                @Override
                public void run() {
                    log.info("scheduled run");
                }
            },1,3,TimeUnit.SECONDS);
    
            //  timer schedule 
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    log.info("timer run");
                }
            },new Date(),5*1000);
  • Executors.newSingleThreadExecutor

  • 単一スレッド化されたスレッドプールを作成します.タスクは、唯一の作業スレッドでのみ実行されます.
            ExecutorService executorService = Executors.newSingleThreadExecutor();
    
            for (int i = 0; i < 10; i++) {
                final int index = i;
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                        log.info("task:{}",index);
                    }
                });
            }
    
            executorService.shutdown();

     
    スレッドプールの適切な構成:
  • CPU密集型タスクは、できるだけCPUを圧搾する必要があり、参考値はNCPU+1に設定することができる.
  • IO密集型タスクで、参照値は2*NCPUに設定できます.