线程池
new Thread()弊端
每次new Thread新建对象,性能差
线程缺乏统一管理,可能无限的新建线程,相互竞争,有可能占用过多系统资源导致死机
线程池的好处
重用已存在的线程,减少对象创建、消亡开销,性能佳
可有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞
提供定时执行、定期执行、单线程、并发控制能高级功能
corePoolSize:核心线程数量
maximumPoolSize:线程最大线程数
workQueue:阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程中产生重大影响
三者的关系:如果运行线程数少于corePoolSize,直接创建新线程来处理任务,即使线程池其它线程是空闲的,如果线程池的线程数量大于等于corePoolSize并且小于maxmumPoolSize的时候,则只有当workQueue满的时候,才创建新的线程来处理任务,如果我们设置corePoolSize和maxmumPoolSize值相同时,那么创建线程池大小时固定的,如果有新任务提交,在workQueue还没有满的时候,就把请求放到workQueue里面等待有空闲的线程就从里面取出任务进行处理如果我们的线程数量大于设置的maxmumPoolSize,workQueue也已经满了,那么就通过拒绝策略(rejectHandler)来指定策略来处理任务
KeepAliveTime:线程没有任务执行时最多保持多久时间终止
unit:keepAliveTime的时间单位
threadFactory:线程工厂,用来创建工厂
rejectHandler:当拒绝处理任务时的策略,线程池有4种策略,1、直接抛出异常,默认策略。2、用调用者所在的线程来处理任务,3、丢弃队列中最靠前的任务,并执行当前任务。4、直接丢弃任务
线程状态
1、新建状态(New):新创建了一个线程对象。
2、就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于“可运行线程池”中,变得可运行,只等待获取CPU的使用权。即在就绪状态的进程除****CPU之外,其它的运行所需资源都已全部获得。
**3、运行状态(Running):**就绪状态的线程获取了CPU,执行程序代码。
**4、阻塞状态(Blocked):**阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。
阻塞的情况分三种:
(1)、等待阻塞:运行的线程执行wait()方法,该线程会释放占用的所有资源,JVM会把该线程放入“**等待池”**中。进入这个状态后,是不能自动唤醒的,必须依靠其他线程调用notify()或notifyAll()方法才能被唤醒,
(2)、同步阻塞:运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入**“锁池”**中。
(3)、其他阻塞:运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
**5、死亡状态(Dead):**线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
ThreadPoolExecutor
execute():提交任务,交给线程池来执行
submit():提交任务,能够返回执行结果,execute+Future
Shutdown():关闭线程池,等待任务执行完成
shutdownNow():关闭线程池,不等待任务执行完成,会关闭正在执行的线程
getTaskCount():线程池已执行和未执行的任务的总数
getCompletedTaskCount():已完成的任务总数
getPoolSize():线程池当前的任务数量
getActiveCount():当前线程池中正在执行的任务数量
Executor框架接口
Executors.newCachedThreadPool:可缓存的线程池,如果线程池超过了处理需要,可以灵活回收,如果没有可以回收的,那么创建一个新的线程
Executors.newFixedThreadPool:创建的一个固定线程池,可以控制线程最大并发数,超出的线程会在队列中等待,
Executors.newScheduledThreadPool:创建的也是一个定长线程池,支持定时以及定期性的执行
Executores.newSingleThreadPool:创建一个单线程线程池,它只会用唯一的一个工作线程来执行任务,保证所有任务按指定顺序来执行任务,按照先入先出,优先级来执行任务
使用实例
public static void main(String[] args){
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
// scheduledExecutorService.schedule(new Runnable() {
// @Override
// public void run() {
// log.info("run");
// }
// },3,TimeUnit.SECONDS)
// scheduledExecutorService.shutdown();
// scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
// @Override
// public void run() {
// log.info("run");
//
// }
// },1,3,TimeUnit.SECONDS);
Timer timer=new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
log.info("run1");
}
},new Date(),5*1000);
}
线程池合理配置
根据任务类型来配置线程池大小
CPU密集型任务,就需要尽量压榨CPU,参考值可以设置为NCPU+1
IO密集型任务,参考值可以设置为2*NCPU