Java 並行スレッドプールとソースコード分析の基本原理の詳細な説明

1. スレッドプールとスレッド性能の比較

シングルスレッドの場合, タスクの処理速度はスレッドプールを使用するパフォーマンスと比較して大幅に改善されます. スレッドプールは内部で再利用できます. スレッドがタスクを処理した後, スレッドプールに戻って他のタスクを処理することができます.これにより、スレッドの破棄と作成時間が大幅に短縮されます。

Java に付属するいくつかのスレッド プール:

ExecutorService executorService = Executors.newCachedThreadPool(); 
ExecutorService executorService1 = Executors.newFixedThreadPool(100); 
ExecutorService executorService2 = Executors.newSingleThreadExecutor(); 
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);

上記のスレッド プールの構築パラメータはすべて ThreadPoolExecutor で作成されますが、使用されるパラメータは異なります。

newCachedThreadPool で使用される構築方法: 対応するパラメーター (コア スレッドの数、スレッドの最大数、スレッドの生存時間、スレッドの生存時間の単位、キュー)、newCachedThreadPool はコア スレッドが 0 しかなく、一時的なスレッドの数は無限になる可能性があるため、その実行効率は非常に高く、SynchronousQueue は典型的な生産者消費者モデルであり、アウトソーシング会社に相当します。

new ThreadPoolExecutor(0, Integer.MAX_VALUE, 
                              60L, TimeUnit.SECONDS, 
                              new SynchronousQueue<Runnable>())
newCachedThreadPool で使用される構築方法: コア スレッドの数と一時スレッドの数は両方ともカスタマイズされます. LinkedBlockingQueue キューは無制限のブロッキング キューであり、タスクの処理を無期限に待機することと同じですが、効率は非常に低くなります. 国有企業に相当します。
new ThreadPoolExecutor(nThreads, nThreads, 
                              0L, TimeUnit.MILLISECONDS, 
                              new LinkedBlockingQueue<Runnable>())
newSingleThreadExecutor で使用される構築方法: コア スレッドの数と一時スレッドの数は両方とも 1 であり、これは 1 人が無数のタスクを処理することに相当します. タスクをすばやく処理できると効率は非常に速くなりますが、遅くなります.タスクを処理する必要がある場合、非常に効率が悪いと思われます。民間企業に相当し、すべてを一人で行います。
新しい FinalizableDelegatedExecutorService 
    (新しい ThreadPoolExecutor(1, 1, 
                            0L, TimeUnit. MILLISECONDS,
                            新しい LinkedBlockingQueue<Runnable>()))

OOM を持つ可能性が最も高いスレッド プール: 無制限のキューではない newCachedThreadPool は、メモリの最大値に達すると OOM を報告します。

前の 3 つのケースは Ali の仕様では推奨されていませんが、上記の 3 つはメモリの上限値に到達できないビジネスで使用できます. Ali はカスタム スレッド プール ThreadPoolExecutor を推奨しています

 1.1 実際のスレッドプールの比較

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadDemo {

    public static void main(String[] args) {

        //定义3个线程池
        ExecutorService executorService = Executors.newCachedThreadPool();//很快
        ExecutorService executorService1 = Executors.newFixedThreadPool(100);//不快不慢
        ExecutorService executorService2 = Executors.newSingleThreadExecutor();//最慢

        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            executorService2.submit(new Task());
        }
        executorService.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }
}

1.2 ThreadPool Executor 戦闘

/**
 * 第31个任务会拒绝任务
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //定义ThreadPoolExecutor
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10));
        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            threadPoolExecutor.submit(new Task());
        }
        threadPoolExecutor.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

1.3 インタビューの質問 1: カスタム スレッド プールのパラメーター

public ThreadPoolExecutor(int corePoolSize, 
                          int maximumPoolSize, 
                          long keepAliveTime, 
                          TimeUnit unit, 
                          BlockingQueue<Runnable> workQueue, 
                          ThreadFactory threadFactory, 
                          RejectedExecutionHandler handler) {
   
   

corePoolSize: コアスレッドの数

int maximumPoolSize: スレッドの最大数

long keepAliveTime: 一時的なスレッドの存続時間

TimeUnit 単位: 一時スレッド サバイバル ユニット

BlockingQueue<Runnable> workQueue: タスク キュー

ThreadFactory threadFactory: 一般的なカスタム ファクトリ クラス

RejectedExecutionHandler ハンドラー: 拒否戦略、4 つの定義があります。通常、拒否戦略をカスタマイズできます。

AbortPolicy: RejectedExecutionException がデフォルトでスローされ、タスクが拒否されます
DiscardPolicy: タスクを放棄します
DiscardOldestPolicy: キュー構造を介して最も古いタスクをスローします
CallerRunsPolicy: execute メソッドを呼び出すスレッドがタスクを実行します

1.4 インタビューの質問スレッド プールのソース コード分析の実行図 (TODO) 

1.5 インタビューの質問における submit() メソッドと execute メソッドの違い (TODO)

投入と実行の違い:スレッドには投入優先度と実行優先度という概念があり、投入優先度は実行優先度よりも高い。
1. execute メソッドは submit メソッドにあります。
2. submit メソッドは Future ジェネリック関数を返しますが、execute は返しません。

 

 

1.6 インタビューの質問における offer() と add() の違い

add と offer はどちらも、タスク キューにタスクを追加するためのメソッドです. 違いは、add メソッドは例外をスローしないのに対し、offer は割り込み例外をスローすることです. これが両者の唯一の違いです.

 

 

1.7 newScheduledThreadPool(TODO)

1.7.1 newScheduledThreadPool 戦闘 (TODO)

1.7.2 ソースコード分析 (TODO)

1.8 カスタム拒否ポリシー

拒否ポリシーをカスタマイズするには、次の 2 つの方法があります。

//カスタム拒否戦略
RejectedExecutionHandler rejectExecutionHandler = new RejectedExecutionHandler() { 
    @Override 
    public void rejectExecution(Runnable r, ThreadPoolExecutor executor) { 
        System.out.println("カスタム拒否戦略、データベースに保存できます"); 
    } 
;

2 番目の方法: RejectedExecutionHandler インターフェースを実装し、rejectedExecution メソッドを書き直します。

import java.util.concurrent.*;

/**
 * 第31个任务会拒绝任务
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //自定义拒绝策略
        RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                System.out.println("自定义拒绝策略,可以存入数据库");
            }
        };

        //定义ThreadPoolExecutor
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 30, 0, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(10),rejectedExecutionHandler);
        //定义100个任务给线程池处理对比处理性能
        long begin = System.currentTimeMillis();
        for(int i=0;i<100;i++){
            threadPoolExecutor.submit(new Task());
        }
        threadPoolExecutor.shutdown();
        long end = System.currentTimeMillis();
        System.out.println("处理时间:"+(end-begin)/1000+"秒");
    }
}

class Task implements Runnable{

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"处理完任务");
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

おすすめ

転載: blog.csdn.net/qq_21575929/article/details/124939077