1.为什么用线程池:
1.cpu数量有限,只能并发执行确定个数的线程。
2.使用线程池可以复用线程,可以减少线程创建和销毁造成的资源浪费。
3.方便管理已经创建的线程。
2.线程池的参数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize:核心线程数
maximumPoolSize:最大线程数
keepAliveTime:非核心线程在没有线程执行的情况下最大存活时间
unit:存活时间的单位
workQueue:任务队列
threadFactory:线程工厂
RejectedExecutionHandler:拒绝策略
3.线程池的运行流程:
先将任务提交到核心线程执行,核心线程已满则将任务加入到阻塞队列中,阻塞队列已满则采用拒绝策略。
4.拒绝策略:
AbortPolicy(中止策略):丢弃任务,并直接抛出RejectedExectionException异常组织系统正常运行
DiscardPolicy:丢弃任务,但是不抛出异常,什么都不做。
CallerRunsPolicy():谁提交该任务,就调用谁的线程去执行该任务。如果线程池都关闭了,那就直接抛弃掉该任务。
DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前提交的任务重新提到线程池。
5.几种常见的线程池:
1.newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
corePoolSize=maxPoolSize 即不能创建非核心线程
阻塞队列采用LinkedBlockingQueue
2.newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
corePoolSize=maxPoolSize=1 即只能创建一个线程
阻塞队列采用LinkedBlockingQueue
3.newCachedThreadPool
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
corePoolSize=0 ,maxPoolSize=Integer.MAX_VALUE 即所有线程都是非核心线程,几乎可以无限制的创建非核心线程
阻塞队列采用SynchronousQueue
4.newScheduledThreadPool
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue(), threadFactory); }
6.线程池的继承图:
Exectors提供了几种线程池的实现类,其实就是实现了ThreadPoolExector
阿里禁止使用Exectors提供的几种线程池,需要开发人员手动实现ThreadPoolExector