九.线程池
线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池可以事先创建多个线程,等待着CPU分配执行任务,执行完之后返回池中等待下一次任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度,优化资源的使用。
三大方法:
- ExecutorService service = Executors.newSingleThreadExecutor(); 创建一个使用从*队列运行的单个工作线程的执行程序
- ExecutorService service = Executors.newFixedThreadPool(int nThreads); 创建一个线程池,该线程池重用固定数量的从共享*队列中运行的线程。
- ExecutorService service = Executors.newCachedThreadPool(); 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程
-
public class Executor1 { public static void main(String[] args) { // ExecutorService service = Executors.newSingleThreadExecutor(); // 创建单个线程 // ExecutorService service = Executors.newFixedThreadPool(3); // 创建固定线程数的线程池 ExecutorService service = Executors.newCachedThreadPool(); // 可变数量线程数的线程池 try { for (int i = 1; i <= 15; i++) { service.execute(()->{ System.out.println(Thread.currentThread().getName()+" start"); }); } } catch (Exception e) { e.printStackTrace(); } finally { service.shutdown(); } } }
七大参数:
- int corePoolSize 核心线程数
- int maximumPoolSize 最大线程数
- long keepAliveTime 除核心线程以外多余空闲线程的等待时间,超过会被终止
- TimeUnit unit 等待时间单位
- BlockingQueue<Runnable> workQueue 阻塞队列(任务等待执行队列)
- ThreadFactory threadFactory 线程工厂,一般不用改动
- RejectedExecutionHandler handler 拒绝策略,任务队列已满且执行任务的线程数大于最大线程数时启用
自定义线程池
public class Threadpool {
public static void main(String[] args) {
/* 拒绝策略
AbortPolicy() 被拒绝的任务的处理程序,抛出一个 RejectedExecutionException
CallerRunsPolicy() 一个被拒绝的任务的处理程序,直接在 execute方法的调用线程中运行被拒绝的任务,除非执行程序已经被关闭,否则这个任务被丢弃
DiscardOldestPolicy() 被拒绝的任务的处理程序,丢弃最旧的未处理请求,然后重试 execute ,除非执行程序关闭,在这种情况下,任务被丢弃
DiscardPolicy() 被拒绝的任务的处理程序静默地丢弃被拒绝的任务
*/
ExecutorService service = new ThreadPoolExecutor(
2,//核心线程数
6,//最大线程数
3,//等待时间
TimeUnit.SECONDS,//时间单位
new ArrayBlockingQueue<>(3),//阻塞队列
Executors.defaultThreadFactory(),//默认的线程工厂
new ThreadPoolExecutor.DiscardOldestPolicy()
);
try {
for (int i = 1; i <= 15; i++) {
service.execute(()->{
System.out.println(Thread.currentThread().getName()+" start");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
service.shutdown();
}
}
}
如何确定最大线程数(maximumPoolSize):
获取CPU核数:
Runtime.getRuntime().availableProcessors()
- CPU密集型:(系统的硬盘、内存性能相对CPU要好很多,即需要大量的运算) 可设置为CPU核数。 参考:cores+1
- I/O密集型:(系统的CPU性能相对硬盘、内存要好很多,即需要大量的I/O操作) 大于I/O十分耗时的任务数量的2倍。参考:2 * cores