线程池
1.优点
1. 降低资源消耗(线程复用)
2. 提高响应速度
3. 可管理线程
2.自定义线程池
public class ThreadPoolExecutorDemo {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
2,
4,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.CallerRunsPolicy()
);
try {
for (int i = 1; i <= 100; i++) {
threadPoolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+"==>");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
threadPoolExecutor.shutdown();
}
}
}
3.阻塞队列
ArrayBlockingQueue:基于数组结构的有界阻塞队列,按先进先出对元素进行排序。
LinkedBlockingQueue:基于链表结构的有界/无界阻塞队列,按先进先出对元素进行排序,吞吐量通常高于 ArrayBlockingQueue。Executors.newFixedThreadPool 使用了该队列。
SynchronousQueue:不是一个真正的队列,而是一种在线程之间移交的机制。要将一个元素放入 SynchronousQueue 中,必须有另一个线程正在等待接受这个元素。如果没有线程等待,并且线程池的当前大小小于最大值,那么线程池将创建一个线程,否则根据拒绝策略,这个任务将被拒绝。使用直接移交将更高效,因为任务会直接移交给执行它的线程,而不是被放在队列中,然后由工作线程从队列中提取任务。只有当线程池是无界的或者可以拒绝任务时,该队列才有实际价值。Executors.newCachedThreadPool使用了该队列。
PriorityBlockingQueue:具有优先级的无界队列,按优先级对元素进行排序。元素的优先级是通过自然顺序或 Comparator 来定义的。
4.拒绝策略
new ThreadPoolExecutor.CallerRunsPolicy()
5. 执行流程
先使用核心线程池处理任务,多余的任务放入阻塞队列中,队列满后使用救急线程,当线程数达到最大线程数后,使用拒绝策略
6.如何合理的配置线程池的最大线程数?
先判断是CPU密集型还是IO密集型
CPU密集型,设置线程数 = CPU数 + 1,通常能实现最优的利用率
Runtime.getRuntime().availableProcessors()
IO密集型,设置 线程数 = CPU数 * 2