スレッドの再利用を実現し、スレッドの再作成や破棄を回避できます。スレッドの作成と破棄は、CPU にとって非常に負荷がかかります。
作成できるスレッドの最大数を制限し、マシンのパフォーマンスに応じてスレッド プールのパラメーターを動的に調整して、アプリケーションのパフォーマンスを向上させることができます。
スケジュール実行や同時実行制御などの機能を提供します。
ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 10; i++) { final int finalI = i; executorService.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS, new SynchronousQueue()); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); }上記の 2 つのコード スニペットから、CachedThreadPool の MaximumPoolSize が整数の最大値 2147483647 であることがわかります。これは、無制限のスレッド作成とスレッドの作成に相当します。メモリが必要です。はい、これによりメモリ オーバーフローが発生します。通常のマシンでは、これほど大量のスレッドを作成するためにそれほど大きなメモリを使用することはありません。 固定容量スレッド プールFixedThreadPoolnewFixedThreadPool(int num)、num は指定する固定スレッドの数です
ExecutorService executorService = Executors.newFixedThreadPool(5); for (int i = 0; i < 10; i++) { final int finalI = i; executorService.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }出力:
pool-1-thread-575b3c38ff368dcafe01d2cfbd3d86ea2run>4スレッドの再利用が実現されていることがわかります。 FixedThreadPool が固定スレッド プールであるのはなぜですか? ソース コード分析pool-1-thread-475b3c38ff368dcafe01d2cfbd3d86ea2run>3
pool-1-thread-575b3c38ff368dcafe01d2cfbd3d86ea2 run> 5
pool-1-thread-375b3c38ff368dcafe01d2cfbd3d86ea2run>2
pool-1-thread-375b3c38ff368dcafe01d2cfbd3d86ea2run>8
pool-1-thread-3b515038e79715e2588b433552eb233c0run>9
pool-1-thread-275b3c38ff368dcafe01d2cfbd3d86ea2run>1
pool-1-thread-175b3c38ff368dcafe01d2cfbd3d86ea2run>0
pool-1- thread- 575b3c38ff368dcafe01d2cfbd3d86ea2run>7
pool-1-thread-475b3c38ff368dcafe01d2cfbd3d86ea2run>6
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); }このソース コードから、コア スレッドの数 (corePoolSize) と最大スレッド数 (maximumPoolSize) が両方とも nThread であることがわかります。この場合、スレッド プールは拡張されず、スレッドの数は固定されます。 シングル スレッド プール SingleThreadExecutor
ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 10; i++) { final int finalI = i; executorService.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
public static ExecutorService newSingleThreadExecutor() { return new Executors.FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); }このソース コードから、コア スレッド数 (corePoolSize) と最大スレッド数 (maximumPoolSize) が両方とも 1 であることがわかります。 1つのスレッド。 Scheduled ThreadPool
int initDelay=10; //初始化延时 int period=1;//初始化延迟过了之后,每秒的延时 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"); } },initDelay,period, TimeUnit.SECONDS);
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, 2147483647, 10L, TimeUnit.MILLISECONDS, new ScheduledThreadPoolExecutor.DelayedWorkQueue()); }ScheduledThreadPoolの最大スレッド数(maximumPoolSize)は整数の最大値2147483647となっており、これはスレッドを無制限に作成することと同等であることがわかります。スレッドはメモリを必要とするため、メモリ オーバーフローが発生します。通常のマシンでは、これほど多くのスレッドを作成するためにそれほど大きなメモリを使用することはありません。 ThreadPoolExecutor はスレッド プールを作成します (強く推奨)
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 12; i++) { final int finalI = i; threadPoolExecutor.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); }
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { }
public ArrayBlockingQueue(int capacity) { this(capacity, false); }LinkedBlockingQueue: 無制限のブロッキング キュー。キューにはサイズ制限がないため、メモリ オーバーフローが発生する可能性があります。
public LinkedBlockingQueue() { this(2147483647); }handlerAbortPolicy: 例外を直接スローします。
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()); } }DiscardPolicy: 操作は実行されません。タスクをサイレントに破棄します
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }DiscardOldestPolicy: 最長の既存タスクを破棄します
public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }CallerRunsPolicy: タスクを送信したスレッドにタスクを処理させます
public static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }threadFactory
ThreadFactory threadFactory = Executors.defaultThreadFactory(); threadFactory.newThread(new Runnable() { @Override public void run() { System.out.println("threadFactory"); } }).start();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 2L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(5), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); for (int i = 0; i < 26; i++) { //并发数26 final int finalI = i; threadPoolExecutor.execute(new Runnable() { public void run() { System.out.println(Thread.currentThread().getName()+"<thread->run>"+ finalI); } }); } /** * 核心线程数=10,最大线程数=20,故可扩容线程数=20-10 * BlockingQueue的大小为5,故等待区的大小为5,也就是当并发数<=核心线程数+5不会扩容,并发数大于16才会扩容 * * 触发扩容:并发数>核心线程数+阻塞队列的大小 * 对于这段代码,如果来了26个并发,10个并发会被核心线程处理,5个会在等待区,剩下11个会因为等待区满了而触发扩容 * 因为这里最多能够扩容10个,这里却是11个,所以会触发拒绝策略 */
为什么这段代码会触发拒绝策略
对于这段代码,如果来了26个并发,10个并发会被核心线程处理,5个会在等待区,剩下11个会因为等待区满了而触发扩容,但是又因为因为这里最多能够扩容10个,这里却是11个,所以会触发拒绝策略。
怎么触发扩容
触发扩容:并发数>核心线程数(corePoolSize)+阻塞队列(workQueue)的大小
使用Java纯手写一个线程池
以上がJavaスレッドプールを作成する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。