Java 线程池
1. 池化技术
A. 程序运行的本质:占用系统资源,CPU/磁盘网络进行使用;
B. 池有线程池、连接池、内存池、对象池等,因为线程的创建和销毁,数据库的连接和断开都很耗资源;
C. 池化技术就是提前准备一些资源,以供使用。
2. 线程池作用
A. 重用存在的线程,减少对象创建、消亡的开销,性能佳;
B. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞;
C. 提供定时执行、定期执行、单线程、并发数控制等功能。
3. 线程池创建方式(Executors类)
A. ExecutorService executorService = Executors.newFixedThreadPool(5):重用指定数目的线程,其背后使用的是无界的工作队列,任何时候最多有nThreads个工作线程是活动的,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现,如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目nThreads;
B. ExecutorService executorService = Executors.newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,特点是它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程,如果线程闲置的时间超 60秒,则被终止并移出缓存,长时间闲置时,这种线程池,不会消耗什么资源,其内部使用SynchronousQueue作为工作队列;
C. ExecutorService executorService = Executors.newSingleThreadExecutor():特点在于工作线程数目被限制为1,操作一个无界的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
D. ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor():创建单线程池,可以进行定时或周期性的工作调度;
E. ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5):可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程;
F. ExecutorService executorService = Executors.newWorkStealingPool():Java 8才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;
G. ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor():是最原始的线程池创建;
注意:阿里巴巴不允许使用Executors去创建线程池,规避资源耗尽的风险,推荐最后一种。
4. 线程池七大参数
A. corePoolSize:核心线程的数量;
B. maximumPoolSize:最大线程的数量;
C. keepAliveTime:空闲线程保留的时间,默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用;
D. unit:keepAliveTime的时间单位;
TimeUnit.DAYS; // 天 TimeUnit.HOURS; // 小时 TimeUnit.MINUTES; // 分钟 TimeUnit.SECONDS; // 秒 TimeUnit.MILLISECONDS; // 毫秒 TimeUnit.MICROSECONDS; // 微妙 TimeUnit.NANOSECONDS; // 纳秒
E. workQueue:阻塞队列,用来存储等待执行的任务;
ArrayBlockingQueue // 基于数组的先进先出队列,此队列创建时必须指定大小
LinkedBlockingQueue // 基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE
SynchronousQueue // 这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务
F. threadFactory:线程工厂,主要用来创建线程;
G. handler:拒绝处理任务时的策略。
ThreadPoolExecutor.AbortPolicy // 丢弃任务并抛出RejectedExecutionException异常(默认策略)
ThreadPoolExecutor.DiscardPolicy // 也是丢弃任务,但是不抛出异常
ThreadPoolExecutor.DiscardOldestPolicy // 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy // 由调用线程处理该任务
5. 线程池的状态
A. RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务;
B. SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务;
C. STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程;
E. TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated();
F. TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。
6. ExecutorService方法
A. execute():只能执行Runnable类型的任务;
B. submit():可以执行Runnable和Callable类型的任务;
C. shutdown():不会立即终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务;
D. shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务。
7. 线程池工作流程
A. 当线程池数量小于corePoolSize时,新提交任务将创建一个新线程执行任务,即使此时线程池中存在空闲线程;
B. 当线程池数量达到corePoolSize时,新提交任务将被放入workQueue中,等待线程池中任务调度执行;
C. 当workQueue队列已满,且maximumPoolSize>corePoolSize时,新提交任务会创建新线程执行任务;
D. 当提交任务数创建的线程超过maximumPoolSize时,新提交任务由RejectedExecutionHandler处理;
E. 当线程池中超过corePoolSize线程,空闲时间达到keepAliveTime时,关闭空闲线程;
F. 当设置allowCoreThreadTimeOut(true)时,线程池中corePoolSize线程空闲时间达到keepAliveTime也将关闭。