1. 复用线程,减少线程创建和销毁带来的开销
2. 主动控制线程数量,完成并发控制
3. 简化对线程的管理难度
可以不用线程池吗?可以,对于简单的多线程任务可直接new Thread处理。如果不使用线程池,还想减少开销的话,需要自行管理线程。
四个常用构造器public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue);
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);
主要涉及的参数:
int corePoolSize:核心线程数。代表线程池主要用来执行任务的线程的数量。
int maximumPoolSize:最大线程数。当核心线程处理不过来的时候,会创建一些非核心线程一起处理。核心线程+非核心线程数的最大值就是最大线程数。
long keepAliveTime:非核心线程的最大空闲时间 。当任务数量逐渐稀疏以后,非核心线程逐渐得以空闲,达到最大空闲时间后,会被线程池销毁。当allowCoreThreadTimeout()设置为true时,核心线程也不例外,超过最大空闲时间也会被销毁。
TimeUnit unit:keepAliveTime的时间单位
BlockingQueue workQueue:阻塞队列。 当前核心线程达到最大值时,优先向阻塞队列进行填充。
LinkedBlockingQueue
链式阻塞队列,底层数据结构是链表,默认大小是
Integer.MAX_VALUE
,也可以指定大小。ArrayBlockingQueue
数组阻塞队列,底层数据结构是数组,需要指定队列的大小。
SynchronousQueue
同步队列,内部容量为0,每个put *** 作必须等待一个take *** 作,反之亦然。
DelayQueue
延迟队列,该队列中的元素只有当其指定的延迟时间到了,才能够从队列中获取到该元素 。
ThreadFactory threadFactory:线程工厂,用于为线程池提供线程。如果不指定,会采用默认的工厂。
static class DefaultThreadFactory implements ThreadFactory { // 省略属性 // 构造函数 DefaultThreadFactory() { SecurityManager s = System.getSecurityManager(); group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); namePrefix = "pool-" + poolNumber.getAndIncrement() + "-thread-"; } // 省略 }
shutdown和shutdownNow的区别RejectedExecutionHandler handler:拒绝策略。当线程达到最大线程数时,将采用拒绝策略处理后续的任务。
ThreadPoolExecutor.AbortPolicy:默认拒绝处理策略,丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:丢弃新来的任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列头部(最旧的)的任务,然后重新尝试执行程序(如果再次失败,重复此过程)。
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务。
-
调用shutdown()方法后线程池不能接受新的任务,清除一些空闲worker,不会等待阻塞队列的任务完成。
-
调用shutdownNow()方法后线程池不能接受新的任务,中断所有线程,阻塞队列中没有被执行的任务全部丢弃。此时,poolsize=0,阻塞队列的size也为0
- 线程总数量 < corePoolSize,无论线程是否空闲,都会新建一个核心线程执行任务。注意,这一步需要获得全局锁。
- 线程总数量 >= corePoolSize时,新来的线程任务会进入任务队列中等待,然后空闲的核心线程会依次去缓存队列中取任务来执行。
- 缓存队列满了,会创建非核心线程去执行这个任务。注意,这一步需要获得全局锁。
- 缓存队列满了, 且总线程数达到了maximumPoolSize,则会采取拒绝策略进行处理。
几种常见的线程池
newCachedThreadPool:缓存队列。特点:核心线程数为0,来一个任务就创建一个线程,容易造成线程数过大的问题。
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue
()); }
newFixedThreadPool:固定线程数。特点:核心线程数等于最大线程数,没有非核心线程。通过等待队列实现处理速度的控制。容易造成OOM。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue
()); }
newScheduledThreadPool:定时处理线程池。特点:支持定时或周期性执行任务。也容易OOM
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } //ScheduledThreadPoolExecutor(): public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, new DelayedWorkQueue()); }
newSingleThreadExecutor:单线程。特点:核心线程数等于最大线程数等于1,没有非核心线程。通过等待队列实现多余任务的处理,容易造成OOM。
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue
())); }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)