线程池
## 线程池
通过例子理解
- 例1
package com.example.test;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.*;
/**
* 核心线程数:5,最大线程数:10,有界阻塞队列长度:5
*
* @author mdl
* @date 2020/5/14 14:21
*/
public class ThreadPoolTest {
public static void main(String[] args) {
int corePoolSize = 5;
int maximumPoolSize = 10;
int queueSize = 5;
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueSize);
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0, TimeUnit.MILLISECONDS,
workQueue, namedThreadFactory, new MyIgnorePolicy());
for(int i =0; i< 10 ;i++){
executor.submit(new Handle());
}
// 效果:打印了前5个任务,10s后打印后5个任务
// 结论1:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理
// ----------------------------------------------------
}
public static class MyIgnorePolicy implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.err.println(r.toString() + " rejected");
}
}
static class Handle implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "--- executor...");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
红框内的再10s后出现的
结论:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理
-
例2
package com.example.test; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.concurrent.*; /** * 核心线程数:5,最大线程数:10,有界阻塞队列长度:5 * * @author mdl * @date 2020/5/14 14:21 */ public class ThreadPoolTest { public static void main(String[] args) { int corePoolSize = 5; int maximumPoolSize = 10; int queueSize = 5; ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build(); BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueSize); ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0, TimeUnit.MILLISECONDS, workQueue, namedThreadFactory, new MyIgnorePolicy()); // for(int i =0; i< 10 ;i++){ // executor.submit(new Handle()); // } // 效果:打印了前5个任务,10s后打印后5个任务 // 结论1:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理 // ---------------------------------------------------- for(int i =0; i< 15 ;i++){ executor.submit(new Handle()); } // 效果:先打印了10个线程执行,10s后打印5个 // 结论:第1~5进来的任务由核心线程执行,第6~10将进入阻塞任务队列,第11~15个任务由临时线程执行 // 核心线程或者临时线程空闲出来后去取阻塞任务队列里的任务执行 } public static class MyIgnorePolicy implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.err.println(r.toString() + " rejected"); } } static class Handle implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName() + "--- executor..."); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
红框里的10s后才显示
结论:第1~5进来的任务由核心线程执行,第6~10将进入阻塞任务队列,第11~15个任务由临时线程执行
核心线程或者临时线程空闲出来后去取阻塞任务队列里的任务执行
-
例3
package com.example.test; import com.google.common.util.concurrent.ThreadFactoryBuilder; import java.util.concurrent.*; /** * 核心线程数:5,最大线程数:10,有界阻塞队列长度:5 * * @author mdl * @date 2020/5/14 14:21 */ public class ThreadPoolTest { public static void main(String[] args) { int corePoolSize = 5; int maximumPoolSize = 10; int queueSize = 5; ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build(); BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(queueSize); ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 0, TimeUnit.MILLISECONDS, workQueue, namedThreadFactory, new MyIgnorePolicy()); // for(int i =0; i< 10 ;i++){ // executor.submit(new Handle()); // } // 效果:打印了前5个任务,10s后打印后5个任务 // 结论1:来了5个任务(假定任务执行时间较长),这时再来任务,将进入阻塞队列,核心线程空闲时处理 // ---------------------------------------------------- // for(int i =0; i< 15 ;i++){ // executor.submit(new Handle()); // } // 效果:先打印了10个线程执行,10s后打印5个 // 结论2:第1~5进来的任务由核心线程执行,第6~10将进入阻塞任务队列,第11~15个任务由临时线程执行 // 核心线程或者临时线程空闲出来后去取阻塞任务队列里的任务执行 for (int i = 0; i < 16; i++) { executor.submit(new Handle()); } // 效果跟2的区别就是第16个任务进来将执行解决策略 } public static class MyIgnorePolicy implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.err.println(r.toString() + " rejected"); } } static class Handle implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName() + "--- executor..."); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } } } }
红框里的10s后出现
跟例2的区别是:第16个任务进来的时候将执行拒绝策略
总结
小于或等于corePoolSize: 创建核心线程处理任务
大于corePoolSize且小于队列长度:进入阻塞队列
大于corePoolSize+队列长度,小于maxPoolSize+队列长度:创建临时线程处理任务
大于maxPoolSize+队列长度:执行拒绝策略
核心线程和临时线程无论谁空闲出来就去阻塞队列里取任务执行
配置
- 高并发、任务执行时间短:线程数设置CPU核数+1(尽量少),目的是减少线程上下文切换
- 高并发、任务执行时间长:
- 数据缓存
- 服务器集群
- 任务拆分,异步解耦
- 并发低、任务执行时间长:
- 瓶颈在磁盘IO, 增加线程数,让CPU都动起来,可以设置CPU核数*2
- 业务计算密集(又叫CPU密集型),线程数设置的少些,减少线程上下文切换,配置CPU核数+1
最大可用的处理器数量
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
每一步脚印都要扎得深一点!