创建方式
1、newSingleThreadExecutor
创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行
2、newFixedThreadPool
创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。如果希望在服务器上使用线程池,建议使用 newFixedThreadPool方法来创建线程池,这样能获得更好的性能。
3、newCachedThreadPool
创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60 秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说 JVM)能够创建的最大线程大小。
4、newScheduledThreadPool
创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
5、newWorkStealingPool
基于 work-stealing 算法的,其中一个任务可以产生其他较小的任务,这些任务被添加到并行处理线程的队列中。如果一个线程完成了工作并且无事可做,则可以从另一线程的队列中"窃取"工作
线程池核心参数
corePoolSize(核心线程数)
(1)核心线程会一直存在,即使没有任务执行;
(2)当线程数小于核心线程数的时候,即使有空闲线程,也会一直创建线程直到达到核心线程数;
(3)设置allowCoreThreadTimeout=true(默认false)时,核心线程会超时关闭。
queueCapacity(任务队列容量)
也叫阻塞队列,当核心线程都在运行,此时再有任务进来,会进入任务队列,排队等待线程执行。
maxPoolSize(最大线程数)
(1)线程池里允许存在的最大线程数量;
(2)当任务队列已满,且线程数量大于等于核心线程数时,会创建新的线程执行任务;
(3)线程池里允许存在的最大线程数量。当任务队列已满,且线程数量大于等于核心线程数时,会创建新的线程执行任务。
keepAliveTime(线程空闲时间)
(1)当线程空闲时间达到keepAliveTime时,线程会退出(关闭),直到线程数等于核心线程数;
(2)如果设置了allowCoreThreadTimeout=true,则线程会退出直到线程数等于零。
allowCoreThreadTimeout(允许核心线程超时)
rejectedExecutionHandler(任务拒绝处理器)
(1)当线程数量达到最大线程数,且任务队列已满时,会拒绝任务;
(2)调用线程池shutdown()方法后,会等待执行完线程池的任务之后,再shutdown()。如果在调用了shutdown()方法和线程池真正shutdown()之间提交任务,会拒绝新任务。
为什么要使用线程池
a.降低资源消耗:重用存在的线程,减少对象创建销毁的开销
b.提高响应速度。可有效地控制并发线程数,提高系统的资源使用率,同时避免过多的资源竞争,避免阻塞,当任务达到时,任务可以不需要等到线程创建才能执行
c.提高线程的管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配,调优和监控。
d.附加功能,提供定时执行 定期执行 单线,并发数的控制。
综上所述使用线程池框架 Executor 能更好的管理线程、提供系统资源使用率
sleep和wait的区别:
1、sleep是Thread的静态方法,wait是Object的方法,任何对象实例都能调用。
2、sleep不会释放锁,它也不需要占用锁。wait会释放锁,但调用它的前提是当前线程占有锁(即代码要在synchronized中)。
3、它们都可以被interrupted方法中断。
ThreadPoolExecutor(线程池)执行顺序
当线程数小于核心线程数时,会一直创建线程直到线程数等于核心线程数;
当线程数等于核心线程数时,新加入的任务会被放到任务队列等待执行;
当任务队列已满,又有新的任务时,会创建线程直到线程数量等于最大线程数;
当线程数等于最大线程数,且任务队列已满时,新加入任务会被拒绝。