Java中的线程池
好处:

ThreadPoolExecutor执行execute方法的4种情况
工作线程:线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,还会循环获取工作队列里的任务来执行
线程池中的线程执行任务分两种
new ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
corePoolSize: 线程池基本大小,提交一个任务到线程池时,会创建一个线程来执行任务,及时其他空闲的能执行,也要创建,等需要执行的任务数大于线程池基本大小时就不再创建。
maximumPoolSize:线程池最大数量,线程池允许创建的最大线程数。如果队列满了,并已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。如果使用了无界任务队列这个参数没什么效果。
keepAliveTime:线程活动保持时间,线程池的工作线程空闲后,保持的存活时间,如果任务很多,并且每个任务执行的时间比较短,可以调大时间 ,提高线程利用率。
TimeUnit unit:线程活动保持时间的单位,天,小时,分钟,毫秒,微秒,纳秒
BlockingQueue workQueue:任务队列,用于保存等待执行的任务的阻塞队列
ThreadFactory threadFactory:用于创建线程的工厂,可以通过线程工厂给每个创建出来的线程设置更有意义的名字。
new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();
RejectedExecutionHandler handler :饱和策略:当队列和线程池都满了,说明线程池处于饱和状态,采用一种策略处理提交的新任务。默认AbortPolicy
AbortPolicy:直接抛出异常
CallerRunsPolicy:只用调用者所在线程来运行任务
DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务
DiscardPolicy:不处理,丢弃掉
自定义处理策略
execute()方法:用于提交不需要返回值的任务,所以无法判断任务是否被线程池执行成功
threadsPool.execute(new Runnable(){
@Override
public void run(){
}
})
submit()方法:用于提交需要返回值的任务,线程池会返回一个future类型对象,通过这个对象可以判断任务是否执行成功,
通过future的get方法获取返回值
get()方法会阻塞当前线程直到任务完成。
get(long timeout,TimeUnit unit)会阻塞当前线程一段时间后立即返回,可能没执行完
Future调用线程池的shutdown或shutdownNow方法关闭线程池,原理:遍历线程池中的工作线程,然后逐个调用线程的interrupt方法中断线程,所以无法响应中断的任务可能永远无法终止。
通常调用shutdown方法来关闭线程池,如果任务不一定要执行完,则可以调用shutdownNow方法。
分析:
任务性质:
CPU密集型任务,IO密集型任务和混合型任务
CPU秘籍型任务应配置尽可能小的线程,如配置N(cpu)+1个线程的线程池
IO密集型任务并不是一直在执行任务,应配置尽可能多的线程,2*N(cpu)
混合型任务,拆分成一个cpu密集任务一个io密集任务,如果任务执行时间相差太大,没必要分解
Runtime.getRuntime().availableProcessors()方法获取设备的CPU个数
任务的优先级:高,中和低
任务的执行时间:长,中和短
任务的依赖性:是否依赖其他系统资源,如数据库连接。、
建议使用有界队列
监控属性