Java ThreadPoolExecutor の拒否ポリシーを実装するにはどうすればよいですか?

WBOY
リリース: 2023-05-08 15:34:08
転載
775 人が閲覧しました

    スレッド プールの基本原理

    スレッド プールの原理は次のとおりです。

    Java ThreadPoolExecutor の拒否ポリシーを実装するにはどうすればよいですか?

    手順:

    • 現在実行中のスレッドの数が corePoolSize 未満の場合は、タスクを実行するための新しいスレッドを作成します。

    • 実行中のスレッドが corePoolSize 以上の場合、タスクはキューに追加されます。

    • タスク キューがいっぱいになると、タスクを処理するために非コアプールに新しいスレッドが作成されます。

    • 新しいスレッドを作成すると、現在実行中のスレッドが MaximumPoolSize を超え、タスクが拒否され、RejectedExecutionHandler.rejectedExecution() メソッドが呼び出されます。

    スレッド プール拒否ポリシー

    スレッド プールには、CallerRunsPolicy、AbortPolicy、DiscardPolicy、DiscardOldestPolicy

    AbortPolicy

    # の 4 つの拒否ポリシーが用意されています。 ##ThreadPoolExecutor のデフォルトの拒否戦略は、AbortPolicy が直接例外をスローすることです。具体的な実装は次のとおりです

    public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() { }
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
    ログイン後にコピー

    説明: この戦略は非常に単純かつ粗雑です。直接 RejectedExecutionException 例外をスローし、実行されませんその後のタスク。

    説明例:

    public class ThreadPoolTest
    {
        public static void main(String[] args)
        {
            ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor(
                    2,
                    5,
                    10,
                    TimeUnit.MICROSECONDS,
                    new LinkedBlockingDeque<>(1),
                    new ThreadPoolExecutor.AbortPolicy());
            
            //异步执行
            for(int i=0; i<10;i++)
            {
              System.out.println("添加第"+i+"个任务");
              threadPoolExecutor.execute(new TestThread("线程"+i));
            }        
        }
    }
    
    public class TestThread implements Runnable
    {
        private String name;
        public TestThread(String name){
            this.name=name;
        }
        
        @Override
        public void run()
        {
            try
            {
                Thread.sleep(1000);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            System.out.println("thread name:"+Thread.currentThread().getName()+",执行:"+name);
        }
    }
    ログイン後にコピー

    実行結果:

    スレッド「メイン」の例外 java.util.concurrent.RejectedExecutionException: タスク com.skywares.fw.juc .thread.TestThread@55f96302 が java.util.concurrent.ThreadPoolExecutor@3d4eac69[実行中、プール サイズ = 5、アクティブ スレッド = 5、キューに入れられたタスク = 1、完了したタスク = 0]

    から拒否されました。 ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
    で java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
    で java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java: 1369)
    com.skywares.fw.juc.thread.ThreadPoolTest.main(ThreadPoolTest.java:26)
    スレッド名:pool-1-thread-5、実行: スレッド 5
    スレッド名:プール-1-スレッド-2、実行: スレッド 1
    スレッド名: プール-1-スレッド-4、実行: スレッド 4
    スレッド名: プール-1-スレッド-3、実行: スレッド 3
    スレッド名: pool-1-thread-1、実行: スレッド 0
    スレッド名: pool-1-thread-5、実行: スレッド 2

    実行結果から、 AbortPolicy 戦略を使用すると、タスクが 7 番目のタスクに実行されるときにエラーが直接報告され、後続のビジネス ロジックは実行されません。

    CallerRunsPolicy

    タスクが拒否された後、CallerRunsPolicy は、実行関数を呼び出す上位スレッドを使用して、拒否されたタスクを実行します。

    関連例

    public class ThreadPoolTest
    {
        public static void main(String[] args)
        {
            ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor(
                    2,
                    5,
                    10,
                    TimeUnit.MICROSECONDS,
                    new LinkedBlockingDeque<>(1),
                    new ThreadPoolExecutor.CallerRunsPolicy());
            
            //异步执行
            for(int i=0; i<10;i++)
            {
              System.out.println("添加第"+i+"个任务");
              threadPoolExecutor.execute(new TestThread("线程"+i));
            }
        }
    }
    ログイン後にコピー

    実行結果:

    0 番目のタスクを追加

    1 番目のタスクを追加
    2 番目のタスクを追加
    3 番目のタスク
    4 番目のタスクを追加
    5 番目のタスクを追加
    6 番目のタスクを追加
    スレッド名:main、実行:スレッド 6
    スレッド名:pool-1-thread-3、実行: スレッド 3
    スレッド名: pool-1-thread-1、実行: スレッド 0
    スレッド名: pool-1-thread-4、実行: スレッド 4
    スレッド名:pool-1-thread -2、実行: スレッド 1
    スレッド名: pool-1-thread-5、実行: スレッド 5
    7 番目のタスクを追加
    8 番目のタスクを追加
    スレッド名:メイン、実行:スレッド8
    スレッド名:pool-1-thread-1,execution:thread 7
    thread name:pool-1-thread-3,execution:thread 2
    9 番目のタスクを追加
    スレッド名: pool-1-thread-1、実行: スレッド 9

    実行結果から、7 番目のタスクが実行されると、スレッド プールの拒否ポリシーにより、このタスクはスレッド プールがアイドル状態のとき、メイン スレッドやその他のタスクは実行され続けます。

    したがって、この戦略はメインスレッドをブロックする可能性があります。

    DiscardPolicy

    この拒否ポリシーは比較的単純です。スレッド プールによって拒否されたタスクは、例外をスローしたり、

    Example

    を実行したりせずに、直接破棄されます。上記のコードを変更し、拒否ポリシーを DiscardPolicy

     ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor(
                    2,
                    5,
                    10,
                    TimeUnit.MICROSECONDS,
                    new LinkedBlockingDeque<>(1),
                    new ThreadPoolExecutor.CallerRunsPolicy());
    ログイン後にコピー

    Execution result

    invoke dealStock success
    goodsId:mobilephone

    thread name:pool-1- thread- に変更します。 1、実行: スレッド 0
    スレッド名: プール-1-スレッド-4、実行: スレッド 4
    スレッド名: プール-1-スレッド-5、実行: スレッド 5
    スレッド名: プール- 1-スレッド-3、実行: スレッド 3
    スレッド名: プール-1-スレッド-2、実行: スレッド 1
    スレッド名: プール-1-スレッド-1、実行: スレッド 2

    実行結果から判断すると、6 つのタスクのみが実行され、他のタスクは放棄されました。

    DiscardOldestPolicy

    DiscardOldestPolicy タスクの追加が拒否された場合、最初にキューに追加されたタスクが破棄され、新しいタスクが追加されます。

    記述例

     ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor(
                    1,
                    2,
                    10,
                    TimeUnit.MICROSECONDS,
                    new LinkedBlockingDeque<>(2),
                    new ThreadPoolExecutor.CallerRunsPolicy());
    ログイン後にコピー

    実行結果:

    0番目のタスクを追加
    1番目のタスクを追加

    2番目のタスクを追加
    3 番目のタスク
    4 番目のタスクを追加
    5 番目のタスクを追加
    dealStock の成功を呼び出す
    goodsId: 携帯電話
    スレッド名:pool-1-thread-2、実行: Thread 3
    スレッド名:pool-1-thread-1、実行:スレッド 0
    スレッド名:pool-1-thread-1、実行:スレッド 2
    スレッド名:pool-1-thread- 2. 実行:スレッド1

    自定义拒绝策略

    当线程池提供的拒绝策略无法满足要求时,我们可以采用自定义的拒绝策略,只需要实现RejectedExecutionHandler接口即可

    public class CustRejectedExecutionHandler implements RejectedExecutionHandler
    {
        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor)
        {
            new Thread(r,"线程:"+new Random().nextInt(10)).start();
        }
    }
    
      ThreadPoolExecutor threadPoolExecutor  = new ThreadPoolExecutor(
                    1,
                    2,
                    10,
                    TimeUnit.MICROSECONDS,
                    new LinkedBlockingDeque<>(2),
                    new CustRejectedExecutionHandler());
    ログイン後にコピー

    执行结果:

    thread name:客户线程:6,执行:线程5
    thread name:pool-1-thread-1,执行:线程0
    thread name:客户线程:8,执行:线程4
    thread name:pool-1-thread-2,执行:线程3
    thread name:pool-1-thread-1,执行:线程1
    thread name:pool-1-thread-2,执行:线程2

    从执行的结果来看,被拒绝的任务都在客户的新线程中执行。

    小结

    • AbortPolicy:直接抛出异常,后续的任务不会执行

    • CallerRunsPolicy:子任务执行的时间过长,可能会阻塞主线程。

    • DiscardPolicy:不抛异常,任务直接丢弃

    • DiscardOldestPolicy;丢弃最先加入队列的任务

    以上がJava ThreadPoolExecutor の拒否ポリシーを実装するにはどうすればよいですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:yisu.com
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!