JAva JUCの4つの一般的なスレッドプール+Springが提供するスレッドプール技術


目次
一.スレッドプールの概念
二.スレッドプールを使用する理由
三.JUCはよく四種類のスレッドプールの作成方式を使う
四.一般的な4種類のスレッドプールの詳細
五.さらなる応用-->Springが提供するスレッドプール技術ThreadPoolTaskExecutorの使用
六.皆さんの読書に感謝します.
一.スレッドプールの概念
        スレッドプールは、プロセス中にタスクをキューに追加し、スレッドの作成後に自動的に開始するマルチスレッド処理形式です.スレッドプールスレッドはバックグラウンドスレッドです.各スレッドは、デフォルトのスタックサイズを使用して、デフォルトの優先度で実行され、マルチスレッドユニットにあります.イベントを待機しているなど、スレッドが管理コードに空きがある場合は、スレッドプールに別の補助スレッドが挿入され、すべてのプロセッサが忙しい状態になります.すべてのスレッド・プール・スレッドが常に多忙であるにもかかわらず、キューに保留中の作業が含まれている場合、スレッド・プールは一定時間後に別の補助スレッドを作成しますが、スレッドの数は最大値を超えません.最大値を超えるスレッドはキューに入れることができますが、他のスレッドが完了するまで起動しません.
二.スレッドプールを使用する理由
1.プログラムの実行中、新しいタスクの呼び出しには新しいスレッドを作成する必要があります.タスクの呼び出しが終了した後、そのスレッドは破棄される必要があります.作成と破棄の過程でリソースがかかります.では、同時発生量が大きい場合、頻繁に作成と破棄すると大量のリソースが消費されます.リソースの消費を減らすために、スレッドプールを選択できます.アプリケーションが開始されると、後で使用するためにスレッドが作成されます.これにより、タスク使用スレッドが終了しても破棄されず、スレッドプールに配置され続けます.これにより、スレッドプールスレッドが多重化され、各タスクの呼び出しコストが削減されます.
2.スレッドプールは、一連のタスクを実行するときにスレッドを管理するなど、リソースの制限と管理の手段を提供し、各ThreadPoolExecutorも、現在のスレッドプールで完了したタスクの数などの基本的な統計データを保持します.
三.JUCはよく四種類のスレッドプールの作成方式を使う
注意:スレッドプールの作成では、Executorsを使用して作成することはできませんが、ThreadPoolExecutorを使用して作成することで、リソースの消費のリスクを回避できます.以下、テストとして使用しますが、その使用について説明するだけなので、Executorsを使用して作成してテストします.
Executorsが作成したスレッドプールオブジェクトの弊害は次のとおりです.
1.FixedThreadPoolとSingleThreadExecutor:
許可されたリクエストキュー長はInteger.MAX_VALUEでは、大量のリクエストが蓄積され、OOMが発生する可能性があります.
2.CachedThreadPoolと ScheduledThreadPool:
許可されたリクエストキュー長はInteger.MAX_VALUEは、大量のスレッドを作成し、OOMを引き起こす可能性があります.
覚えておいてください:実際の操作では、Executorsではなく、ThreadPoolExecutorで作成してください!!!
1.Executors.newSingleThreadExecutor()(単一バックグラウンドスレッド)
2.Executors.newFixedThreadPool(int)(固定サイズラインプール)
3.Executors.newCachedThreadPool()(自動スレッド回収可能)
4.Executors.newScheduledThreadPool(タイミング、遅延スレッドプール)
四.一般的な4種類のスレッドプールの詳細
1. Executors.newSingleThreadExecutor()(単一バックグラウンドスレッド)
        コアスレッド数と最大スレッド数の両方が1のスレッドプールを作成し、ブロックキュー長はInteger.MAX_VALUEは、一意のワーカースレッドのみを作成してタスクを実行し、すべてのタスクが指定された順序(FIFO,LIFO,優先度)で実行されることを保証する一意のワークスレッドのみでタスクを実行します.スレッドの数がコアスレッドの数より多く、現在空いている限り回収されます. 
        このスレッドが異常に終了すると、別のスレッドが置き換えられ、順序が保証されます.単一作業スレッドの最大の特徴は、各タスクを順次実行することを保証し、任意の所定の時間に複数のスレッドがアクティブでないことである.  
使用例は次のとおりです.
public class NewSingleThreadExecutor {

    public static void main(String[] args) {
        ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            //    java 8   lambda    
            // singleThreadExecutor.execute(() -> {})      singleThreadExecutor.execute(new Runnable() {})
            singleThreadExecutor.execute(() -> {
                try {
                    //      : 10          
                    System.out.println(Thread.currentThread().getName() + " index : " + index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

2. 新FixedThreadPool(int)(固定サイズラインプール)
        コアスレッド数と最大スレッド数の両方がnThreadsのスレッドプールを作成し、ブロックキュー長はInteger.MAX_VALUEは、1つのタスクをコミットするたびにワークスレッドを作成し、ワークスレッドの数がスレッドプールの初期の最大数に達した場合、コミットされたタスクをプールキューに格納します.スレッドの数がコアスレッドの数より多く、現在空いている限り回収されます.
        FixedThreadPoolは典型的で優れたスレッドプールであり、スレッドプールがプログラム効率を向上させ、スレッドの作成にかかるコストを節約する利点があります.ただし、スレッドプールが空いている場合、スレッドプールに実行可能なタスクがない場合、ワークスレッドは解放されず、システムリソースも消費されます.
使用例は次のとおりです.
public class NewFixedThreadPool {
    public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
        for (int i = 0; i < 10; i++) {
            final int index = i;
            //    java 8   lambda    
            // fixedThreadPool.execute(() -> {})      fixedThreadPool.execute(new Runnable() {})
            fixedThreadPool.execute(() -> {
                try {
                    //      :          
                    System.out.println(Thread.currentThread().getName() + " index : " + index);
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

3.newCachedThreadPool():(無境界スレッドプール)
        スレッドをオンデマンドで作成するスレッドプールを作成します.スレッドプールの長さが処理の必要性を超えた場合、空きスレッドを柔軟に回収できます.回収できない場合は、新しいスレッドを作成します.初期スレッド数0、最大スレッド数Integer.MAX_VALUE、ブロッキングキューは同期キューです.現在のスレッド60 s内が空いている限り回収される.この特殊な点は、同期キューに追加されたタスクがすぐに実行され、同期キューには最大1つのタスクしかなく、存在するとすぐに実行が出されます.
        ワークスレッドの作成数に制限はほとんどありません(Interger.MAX_VALUEという制限もあります).これにより、スレッドプールにスレッドを柔軟に追加できます.スレッドプールにタスクが長時間コミットされていない場合、つまり、ワークスレッドが指定した時間(デフォルトでは1分)空いている場合、ワークスレッドは自動的に終了します.終了後、新しいタスクをコミットした場合、スレッドプールはワークスレッドを再作成します.CachedThreadPoolを使用する場合は、タスクの数を制御することに注意してください.そうしないと、大量のスレッドが同時に実行されるため、システムがマヒする可能性があります.
使用例は次のとおりです.
public class NewCachedThreadPool {

    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            try {
                Thread.sleep(index * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //    java 8   lambda    
            // cachedThreadPool.execute(() -> {})      cachedThreadPool.execute(new Runnable() {})
            //      :         ,                      ,              
            cachedThreadPool.execute(() -> System.out.println(Thread.currentThread().getName() + " index : " + index));
            cachedThreadPool.execute(() -> System.out.println(Thread.currentThread().getName() + "         index         ,            ,          "));
        }
    }
}

4. 新ScheduledThreadPool(タイミング、遅延スレッドプール)
        最小スレッド数corePoolSizeを作成します.最大はInteger.MAX_です.VALUE、ブロックキューはDelayedWorkQueueのスレッドプールです.       
        定長スレッドプールであり、タイミングおよび周期的なタスク実行をサポートし、タイミングおよび周期的なタスク実行をサポートします.
使用例は次のとおりです.
public class NewScheduleThreadPool {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
        //    java 8   lambda    
        // scheduledThreadPool.execute(() -> {}, delay, unit)      scheduledThreadPool.schedule(new Runnable() {}, delay, unit)
        //    1 :     :     3    
        scheduledThreadPool.schedule(() -> System.out.println(Thread.currentThread().getName() + "   2      "), 2, TimeUnit.SECONDS);

        //    java 8   lambda    
        // scheduledThreadPool.execute(() -> {}, initialDelay, period,unit)      scheduledThreadPool.schedule(new Runnable() {}, initialDelay, period,unit)
        //    2 :     :     6    ,    2      。             ,           5
        scheduledThreadPool.scheduleAtFixedRate(()->{
            System.out.println(Thread.currentThread().getName() + "   6     ,    2      ");
                    try {
                        //          1s    
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                },
                0,
                2,
                TimeUnit.SECONDS);

        // scheduledThreadPool.scheduleWithFixedDelay(() -> {},initialDelay, delay, unit)      scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {}, initialDelay, delay, unit)
        //    3 :     :     6    ,                    2      。             ,           5
        scheduledThreadPool.scheduleWithFixedDelay(()->{
            System.out.println(Thread.currentThread().getName() + "         6    ,       2    ");
                    try {
                        //          1s    
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                },
                6,
                2,
                TimeUnit.SECONDS);


        // todo     scheduleAtFixedRate()   scheduleWithFixedDelay()            ,     ,          (  :       5s  ,       1s,      2s):
        // todo scheduleAtFixedRate():         period ,                (       5s  ,       7s  ,       9s  )
        // todo scheduleWithFixedDelay():        delay ,                         (       5s  ,     6s  ,       8s  ,     9s  ,       11s  )
    }
}

五.さらなる応用-->Springが提供するスレッドプール技術ThreadPoolTaskExecutorの使用
        ThreadPoolTaskExecutorはSpringが提供してくれたスレッドプール技術ですが、これはJUCパッケージのThreadPoolExecutorクラスのパッケージです(装飾者モードに似ています.もちろんSpringが提供する機能はもっと強化されています.タイミングスケジューリング機能もあるので).
        Springパッケージなので、技術は比較的成熟していますが、特に生産環境ではビジネスシーンが満足すれば、これを使うことをお勧めします.
使用例は次のとおりです.
5.1 ThreadPoolTaskExecutorの構成:

        
        
        
        
        
        
        
        
        
        
            
        
    

5.2使用例:
public class ThreadPoolTaskExecutorTest {

    // todo     :          Spring   ,            ,             ,           ,          

    @Autowired
    private static ThreadPoolTaskExecutor threadPoolTaskExecutor;

    public static void main(String[] args) {

        // //    java 8   lambda    
        // threadPoolTaskExecutorTest.execute(() -> {})     threadPoolTaskExecutorTest.execute(new Runnable() {})
        threadPoolTaskExecutorTest.execute(() -> {
            System.out.println("          ");
            //          2s
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("    !");
        });
    }
}

六.皆さんの読書に感謝します.
コードはgithubにアップロードされており、必要なものは自分でダウンロードすることができます.https://github.com/higminteam/practice/tree/master/src/main/java/com/practice/concurrent/threadPool
 
その他のJUCソースの解析に関する記事:
Java JUC(一)のatomic(原子データクラスのパッケージ)を深く理解する
Java JUC(二)のJUCロックメカニズムAQSから再入ロック、読み書きロック、CountDownLatchまでを深く理解する
JAva JUCの4つの一般的なスレッドプール+Springが提供するスレッドプール技術