什么是线程池?
线程池就是提前创建一定线程,放入队列中,根据默认的优先级执行任务,处理完线程不会销毁,而是等待下一个任务。
线程池的优点是什么?为什么要用线程池?
减少线程创建和销毁的消耗,提高线程复用率。频繁创建线程就要考虑用线程池了。
优点也是缺点,线程空闲也会一直占用内存。
说说常用线程池
Java中有三个比较常用的线程池,分别是FixedThreadPool,SingleThreadExecutor,CachedThreadPool。
FixedThreadPool是一个线程数固定的线程池,当这个线程池被创建的时候,池里的线程数就已经固定了。当需要运行的线程数量大体上变化不大时,适合使用这种线程池。固定数量还有一个好处,它可以一次性支付高昂的创建线程的开销,之后再使用的时候就不再需要这种开销。执行顺序:LinkedBlockingQueue FIFO
SingleThreadExecutor是一个线程数量为1的线程池,所有提交的这个线程池的任务都会按照提交的先后顺序排队执行。单个线程执行有个好处:由于任务之间没有并发执行,因此提交到线程池种的任务之间不会相互干扰。程序执行的结果更具有确定性。
CachedThreadPool是一个和缓存有关的线程池,每次有任务提交到线程池的时候,如果池中没有空闲的线程,线程池就会为这个任务创建一个线程,如果有空闲的线程,就会使用已有的空闲线程执行任务。有的人可能会有个疑惑:这样线程不就越来越多了吗?其实不是的,这个线程池还有一个销毁机制,如果一个线程60秒之内没有被使用过,这个线程就会被销毁,这样就节省了很多资源。CachedThreadPool是一个比较通用的线程池,它在多数情况下都能表现出优良的性能。以后编码的时候,遇事不决,用缓存(线程池)。
阻塞队列:
newFixedThreadPool 线程池创建固定数量的线程,从共享无界队列(Integer.MAX_VALUE)中运行。
无界队列:LinkedBlockingQueue
newCachedThreadPool 缓存线程池,根据需要创建线程。
同步队列:SynchronousQueue
newSingleThreadExecutor() 单个线程的线程池。
无界队列:LinkedBlockingQueue
newScheduledThreadPool 周期线程池,可定时执行。
延迟工作队列:DelayedWorkQueue
newSingleThreadScheduledExecutor 单个线程周期线程池。
延迟工作队列:DelayedWorkQueue
线程池的创建
1.直接用Executors(阿里开发手册不建议,因为内部细节不直观)
//Runable
ExecutorService executorService = Executors.newFixedThreadPool(3);//创建定长为3的线程池
executorService.execute(new MyThread());//提交任务到线程池
executorService.shutdown();//关闭线程池
//或者 Callable
/* ExecutorService executorService = Executors.newFixedThreadPool(3);
Future<String> future = executorService.submit(new ExcutorsCallable());
try {
String value = future.get();
System.out.println("----------------" + value);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
executorService.shutdown();
*/
2. ThreadPoolExecutor
ExecutorService executorService1 = new ThreadPoolExecutor(3,//池大小
3,//最大线程数
0L,//线程池中线程空闲时,线程存活的时间,任务多时,可以调大该参数
TimeUnit.MILLISECONDS,//时间单位 毫秒
new LinkedBlockingQueue<Runnable>() //任务队列执行策略
);
共7个参数:核心线程大小、最大线程数、非核心线程超时时间、单位、阻塞队列、线程工厂、拒绝策略handle
如何配置线程池大小?
如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU+1
如果是IO密集型任务,参考值可以设置为2*NCPU
当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。
IO密集型比如:数据库操作