ThreadPoolExecutor実際の戦闘(ソースコードデモ付き)

ThreadPoolExecutorの使用

ThreadPoolExecutorは、次の4つの構築方法を提供します。

img

最後の構築方法(パラメーターが最も多い方法)を使用して、そのパラメーターを説明します。

 public ThreadPoolExecutor(int corePoolSize, 
                              int maximumPoolSize,  
                              long keepAliveTime, 
                              TimeUnit unit, 
                              BlockingQueue<Runnable> workQueue, 
                              ThreadFactory threadFactory,  
                              RejectedExecutionHandler handler ) {
    
     
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
シリアルナンバー 名前 の種類 意味
1 corePoolSize int コアスレッドプールサイズ
2 maximumPoolSize int 最大スレッドプールサイズ
3 keepAliveTime 長いです スレッドの最大アイドル時間
4 単位 TimeUnit 時間単位
5 workQueue BlockingQueue スレッド待機キュー
6 threadFactory ThreadFactory スレッド作成ファクトリ
7 ハンドラ RejectedExecutionHandler 拒否戦略

各パラメータの役割を知った後、私たちは期待に応えるスレッドプールの構築を開始しました。まず、JDKによって事前定義されたいくつかのスレッドプールを確認します。

1つの事前定義されたスレッドプール

1. FixedThreadPool

    public static ExecutorService newFixedThreadPool(int nThreads) {
    
    
        return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
    }
  • corePoolSizeはmaximumPoolSizeと同じです。つまり、そのスレッドはすべてコアスレッドであり、固定サイズのスレッドプールであるという利点があります。
  • keepAliveTime = 0このパラメーターはデフォルトではコアスレッドには無効であり、FixedThreadPoolはすべてコアスレッドです。
  • workQueueはLinkedBlockingQueue(無制限のブロッキングキュー)であり、キューの最大値はInteger.MAX_VALUEです。タスクの送信速度が引き続きタスクの処理速度を超えると、キューに多くの輻輳が発生します。キューが非常に大きいため、ポリシーが拒否される前にメモリがオーバーフローする可能性が非常に高くなります。その欠点は;
  • FixedThreadPoolのタスク実行は無秩序です。

該当するシナリオ:Webサービスの瞬間的なピーククリッピングに使用できますが、長期間の継続的なピーク状態によって引き起こされるキューの輻輳に注意する必要があります。

2. CachedThreadPool

     public static ExecutorService newCachedThreadPool() {
    
    
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
    }
  • corePoolSize = 0、maximumPoolSize = Integer.MAX_VALUE、つまり、スレッドの数はほぼ無制限です。
  • keepAliveTime = 60sの場合、スレッドは60秒間アイドル状態になると自動的に終了します。
  • workQueueはSynchronousQueue同期キューです。このキューはバトンに似ています。CachedThreadPoolスレッドは無制限に作成されるため、キューは同時に配信される必要があります。待機中のキューはありません。SynchronousQueueを使用してください。
  • 該当するシナリオ:要求を受け入れるときのNetty NIOなど、短時間で多数のタスクを高速処理するには、CachedThreadPoolを使用できます。

2. SingleThreadPool

public static ExecutorService newSingleThreadExecutor() {
    
    
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
    }

この外観はnewFixedThreadPool(1)です。FinalizableDelegatedExecutorServiceパッケージの追加レイヤーがあります。このレイヤーの用途は何ですか?説明するドームを作成します。

  public static void main(String[] args) {
    
    
        ExecutorService fixedExecutorService = Executors.newFixedThreadPool(1);
        ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) fixedExecutorService;
        System.out.println(threadPoolExecutor.getMaximumPoolSize());
        threadPoolExecutor.setCorePoolSize(8);
        
        ExecutorService singleExecutorService = Executors.newSingleThreadExecutor();
//      运行时异常 java.lang.ClassCastException
//      ThreadPoolExecutor threadPoolExecutor2 = (ThreadPoolExecutor) singleExecutorService;
    }

比較から、FixedThreadPoolはThreadPoolExecutorに変換でき、そのスレッドプールを構成できますが、SingleThreadExecutorはパッケージ化後に正常に変換できないことがわかります。したがって、SingleThreadExecutorを設定した後は変更できず、実際のSingleが実現されます。

2つのカスタムスレッドプール

Ali標準では、スレッドプールを作成する2番目の方法も推奨しています。

img

以下は、制限付きキュー、カスタムThreadFactory、および拒否戦略を使用したカスタムスレッドプールのデモです。

public class ThreadTest {
    
    

    public static void main(String[] args) throws InterruptedException, IOException {
    
    
        int corePoolSize = 2;
        int maximumPoolSize = 4;
        long keepAliveTime = 10;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
        ThreadFactory threadFactory = new NameTreadFactory();
        RejectedExecutionHandler handler = new MyIgnorePolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                workQueue, threadFactory, handler);
        executor.prestartAllCoreThreads(); // 预启动所有核心线程
        
        for (int i = 1; i <= 10; i++) {
    
    
            MyTask task = new MyTask(String.valueOf(i));
            executor.execute(task);
        }

        System.in.read(); //阻塞主线程
    }

    static class NameTreadFactory implements ThreadFactory {
    
    

        private final AtomicInteger mThreadNum = new AtomicInteger(1);

        @Override
        public Thread newThread(Runnable r) {
    
    
            Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
            System.out.println(t.getName() + " has been created");
            return t;
        }
    }

    public static class MyIgnorePolicy implements RejectedExecutionHandler {
    
    

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
    
    
            doLog(r, e);
        }

        private void doLog(Runnable r, ThreadPoolExecutor e) {
    
    
            // 可做日志记录等
            System.err.println( r.toString() + " rejected");
//          System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
        }
    }

    static class MyTask implements Runnable {
    
    
        private String name;

        public MyTask(String name) {
    
    
            this.name = name;
        }

        @Override
        public void run() {
    
    
            try {
    
    
                System.out.println(this.toString() + " is running!");
                Thread.sleep(3000); //让任务执行慢点
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
        }

        public String getName() {
    
    
            return name;
        }

        @Override
        public String toString() {
    
    
            return "MyTask [name=" + name + "]";
        }
    }
}

出力は次のとおりです。

img

おすすめ

転載: blog.csdn.net/virtual_users/article/details/110239188