一、危害
1)开销大
每次new Thread() 都会创建新的对象,开销较大,无法复用增加垃圾回收的负担。
2)管理困难
每个new Thread() 都是独立的个体,无法有效的管控,无限制创建相互竞争,可能导致oom或者核心业务线程阻塞。
3)功能单一
无法定时执行,中断线程等功能。
二、线程池
1)复用已创建的线程,减少对象创建、消亡的开销,性能佳。
2)可控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
3)可定时执行、中断线程等功能。
三、线程池大小
1)CPU密集型(计算型)
使用较小的线程池,一般是Cpu核心数+1
因为CPU密集型任务CPU的使用率很高,若开过多的线程,只能增加线程上下文的切换次数,带来额外的开销
2)IO密集型(查询访问型)
使用较大的线程池,一般CPU核心数 * 2
因为IO密集型CPU使用率不高,可以让CPU等待IO的时候处理别的任务,充分利用cpu时间
四、线程池创建【使用ThreadPoolExecutor手动创建】
public class CommonThreadPool {
/**
* 线程池对象
*/
public static ExecutorService pool = null;
/**
* 线程池核心池的大小
*/
private static final int CORE_POOL_SIZE = 5;
/**
* 获取当前系统的CPU 数目
*/
private static int cpuNums = Runtime.getRuntime().availableProcessors();
/**
* 线程池的最大线程数
*/
private static final int MAX_POOL_SIZE = (cpuNums * 2) > CORE_POOL_SIZE ? (cpuNums * 2) : CORE_POOL_SIZE;
static {
pool = new ThreadPoolExecutor(
CORE_POOL_SIZE, // 核心线程数
MAX_POOL_SIZE, // 最大线程数 通常核心线程数=最大线程数 当MAX_POOL_SIZE > CORE_POOL_SIZE 时,并不是当核心线程全部被占用后立马开始创建新的线程(只有在队列也满了之后才会开始新建线程)
0L, // 存活时间 >=0 0 永不回收【非核心线程除外】
TimeUnit.MILLISECONDS, // 单位
new ArrayBlockingQueue(100), // 队列 存放待执行任务
new ThreadFactoryBuilder().setNameFormat("CommonThread-%d").build(), // 创建工厂
new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略 默认拒绝 丢弃 丢弃最老的 主线程执行
}
}
五、禁用Executors创建线程池
1)Executors屏蔽的线程池的内部实现细节,开发人员需要根据服务器情况与业务场景定义更合适的线程池。
2)newFixedThreadPool 和 newSingleThreadExecutor的主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至 OOM。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
3)newCachedThreadPool 和 newScheduledThreadPool:主要问题是线程数最大数是 Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至 OOM。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
LinkedBlockingQueue:队列默认大小Integer.MAX_VALUE,未指定大小时可以视为无界队列。
SynchronousQueue:队列大容量为0,不存储任何数据。
DelayedWorkQueue:无界,队列顺序按照延时时长排序。