什么是线程池?
线程池:一种线程使用模式。
线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。
这避免了在处理短时间任务时创建与销毁线程的代价。
线程池不仅能够保证内核的充分利用,还能防止过分调度。
线程池的好处:
1.降低资源消耗
2.提高响应速度
3.方便管理
线程池: 三大方法
创建线程池的三大方法如下:
ExecutorService service = Executors.newSingleThreadExecutor();//单个线程
/*public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}*/
ExecutorService service = Executors.newFixedThreadPool(5);//创建一个固定的线程池的大小
/* public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}*/
ExecutorService service = Executors.newCachedThreadPool();//缓存线程池,可伸缩的
/*public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}*/
在上面三大方法中,本质所有线程池最终都调用的ThreadPoolExecutor来创建线程池的,而ThreadPoolExecutor()方法中有七大参数!
七大参数:
1、int corePoolSize,//核心线程池大小
2、int maximumPoolSize,//最大的线程池大小
3、long keepAliveTime,//存活时间
4、TimeUnit unit,//存活时间的时间单位
5、BlockingQueue<Runnable> workQueue//阻塞队列)
6、ThreadFactory threadFactory,//线程工厂,创建线程的,一般不动
7、RejectedExecutionHandler handler//拒绝策略)
public ThreadPoolExecutor(int corePoolSize,//核心线程池大小
int maximumPoolSize,//最大的线程池大小
long keepAliveTime,//存活时间
TimeUnit unit,//存活时间的时间单位
BlockingQueue<Runnable> workQueue//阻塞队列)
ThreadFactory threadFactory,//线程工厂,创建线程的,一般不动
RejectedExecutionHandler handler//拒绝策略) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
七大参数举例说明:
核心线程大小表示上述图中银行一般情况下开设的窗口(线程数),阻塞队列相当于银行的侯客区,当线程数大于侯客厅+核心线程数的数量时,线程数继续增大时,线程池数的使用依次增加,直至达到最大线程池的大小,达到最大处理线程数还增加的话就会使用拒绝策略!(最大处理线程数=最大线程数+阻塞队列大小)
自定义创建线程池:
ExecutorService threadPool =
new ThreadPoolExecutor(3, //核心线程池大小
5, //最大并发数
10, //超时时间
TimeUnit.SECONDS, //时间单位
new LinkedBlockingQueue<>(),//线程等候队列
Executors.defaultThreadFactory(), //线程创建工厂
new ThreadPoolExecutor.DiscardOldestPolicy());//拒绝策略
最大线程到底应该如何定义?
1、CPU密集型 几核,就是几,可以保证CPU的效率最高
java获取cpu核数的方法:
Runtime.getRuntime().availableProcessors()
2、IO 密集型 判断程序中十分耗I/O的线程, 大于两倍
四种默认的拒绝策略
/**
* new ThreadPoolExecutor.AbortPolicy() 超出最大处理线程抛出异常(最大处理线程数=最大线程数+阻塞队列大小)
* new ThreadPoolExecutor.CallerRunsPolicy() 从哪个线程创建就由那个线程执行(如main线程创建,就在main线程执行)
* new ThreadPoolExecutor.DiscardPolicy() 队列满了不会抛出异常
* new ThreadPoolExecutor.DiscardOldestPolicy() 尝试去和第一个竞争,也不会抛出异常
*/