线程的实现
- Thread
- Runnable
- Callable
什么时候使用线程池?
- 单任务处理时间比较短
- 需要处理的任务量大
线程池的优势
- 重用存在的线程,减少线程创建、销毁的开销,提高性能
- 提高响应速度,任务可以使用线程池中空闲的线程,多任务同时执行
- 提高线程的可管理性,对线程进行统一分配,监控和调优
线程池的状态
- RUNNING 能够接收任务,对已添加的任务进行处理
- SHUTDOWN 不接收任务,但还能处理已添加的任务
- STOP 不接收任务,不处理已添加的任务,而且中断正在执行的任务
- TIDYING 当所有任务都终止,如果想在 TIDYING 状态时执行某些东西,可以重写 terminated() 函数
- TERMINATED 线程池终止
线程池的具体实现
- ThreaPoolExecutor 默认线程池
- ScheduledThreadPoolExecutor 定时线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
参数解析
corePoolSize
线程池中的核心线程数,当提交一个任务时,线程池创建一个新线程执行任务,直到当前线程数等于 corePoolSize;如果当前线程数为 corePoolSize,继续提交的任务被保存到阻塞队列中,等待被执行;如果执行了线程池的 prestartAllCoreThreads() 方法,线程池会提前创建并启动所有核心线程。maximumPoolSize
线程池中允许的最大线程数。如果当前阻塞队列满了,且继续提交任务,则创建新的线程执行任务,前提是当前线程数小于maximumPoolSizekeepAliveTime
线程池维护线程所允许的空闲时间。当线程池中的线程数量大于 corePoolSize 的时候,如果这时没有新的任务提交,核心线程外的线程不会立即销毁,而是会等待,直到等待的时间超过了keepAliveTime;unit
keepAliveTime的单位-
workQueue
用来保存等待被执行的任务的阻塞队列,且任务必须实现Runable接口,在JDK中提供了如下阻塞队列:
(a)、ArrayBlockingQueue:基于数组结构的有界阻塞队列,按FIFO排序任务;(b)、LinkedBlockingQuene:基于链表结构的阻塞队列,按FIFO排序任务,吞吐量通常要高于ArrayBlockingQuene;
(c)、SynchronousQuene:一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene;
(d)、priorityBlockingQuene:具有优先级的无界阻塞队列;
threadFactory
它是ThreadFactory类型的变量,用来创建新线程。默认使用Executors.defaultThreadFactory() 来创建线程。使用默认的 ThreadFactory 来创建线程时,会使新创建的线程具有相同的 NORM_PRIORITY 优先级并且是非守护线程,同时也设置了线程的名称。-
handler
线程池的饱和策略,当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:
(a)、AbortPolicy:直接抛出异常,默认策略;(b)、CallerRunsPolicy:用调用者所在的线程来执行任务;
(c)、DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务;
(d)、DiscardPolicy:直接丢弃任务;
上面的4种策略都是 ThreadPoolExecutor 的内部类。
当然也可以根据应用场景实现 RejectedExecutionHandler 接口,自定义饱和策略,如记录日志或持久化存储不能处理的任务。
线程池监控
public long getTaskCount() //线程池已执行与未执行的任务总数
public long getCompletedTaskCount() //已完成的任务数
public int getPoolSize() //线程池当前的线程数
public int getActiveCount() //线程池中正在执行任务的线程数量