ThreadLocal
为每一个线程赋值一份变量副本(创建一个ThreadLocal对象,用来为每个线程保存一份变量,实现线程封闭)
底层使用一个ThreadLocalMap对象存储
使用ThreadLocal存在内存泄露问题:
使用ThreadLocal对象作为键,是弱引用,可以被回收掉,键为null,但是value值为强引用,不会被回收掉
ThreadLocal正确的使用方法:
建议:每次使用完ThreadLocal都调用它的remove()方法清除数据.
线程池
任务多且简单时,为了减少频繁的创建销毁线程的开销
可以使用线程池,预先创建一部分线程,重复使用,减少创建销毁开销
jdk5自带创建线程池的类:
ThreadPoolExecutor
ThreadPoolExecutor类中的构造器有七个参数:
corePoolSize:核心线程数量(不会被销毁)
1.prestartAllCoreThread() 或者 prestartCoreThread() 方法,预先创建核心数量个线程
2.起初不创建,有任务到达时创建,直到到达核心数量个线程
maximumPoolSize:最大线程数量
keepAliveTime:超出核心数量部分的线程,在没有执行任务的时候,空闲多久后销毁。
unit: keepAliveTime的时间到位,共有六个:
workQueue:指定等待阻塞队列
threadFactory:线程工厂,主要用来创建线程
handle:表示当拒绝处理任务时的策略
线程池的执行
创建完成ThreadPoolExecutor之后,当向线程池提交任务时,通常使用execute方法。execute方法的执行流程图如下:
1.如果线程池中存活的核心线程数小于线程数corePoolSize时,线程池会创建一个核心线程去处理提交的任务。
2.如果线程池核心线程数已满,即线程数已经等于corePoolSize,一个新提交的任务,会被放进任务队列workQueue排队等待执行。
3.当线程池里面存活的线程数已经等于corePoolSize了,并且任务队列workQueue也满,判断线程数是否达到maximumPoolSize,即最大线程数是否已满,如果没到达,创建一个非核心线程执行提交的任务。
4.如果当前的线程数达到了maximumPoolSize,还有新的任务过来的话,直接采用拒绝策略处理。
线程池中的队列
线程池有以下工作队列:
ArrayBlockingQueue:有界队列,是一个用数组实现的有界阻塞队列,按FIFO(先入先出)排序量。
LinkedBlockingQueue:可设置容量队列,基于链表结构的阻塞队列,按FIFO排序任务,容量可以选择进行设置,不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE,吞吐量通常要高于ArrayBlockingQuene;newFixedThreadPool线程池使用了这个队列。
DelayQueue:延迟队列,是一个任务定时周期的延迟执行的队列。根据指定的执行时间从小到大排序,否则根据插入到队列的先后排序。newScheduledThreadPool线程池使用了这个队列。
PriorityBlockingQueue:优先级队列,是具有优先级的无界阻塞队列。
SynchronousQueue:同步队列,一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQuene,newCachedThreadPool线程池使用了这个队列。
线程池的拒绝策略
构造方法的中最后的参数RejectedExecutionHandler用于指定线程池的拒绝策略。当请求任务不断的过来,而系统此时又处理不过来的时候,我们就需要采取对应的策略是拒绝服务。
默认有四种类型:
AbortPolicy策略:该策略会直接抛出异常,阻止系统正常工作。
CallerRunsPolicy策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前的被丢弃的任务。
DiscardOleddestPolicy策略:该策略将丢弃最老的一个请求,也就是即将被执行的任务,并尝试再次提交当前任务。
DiscardPolicy策略:该策略默默的丢弃无法处理的任务,不予任何处理。
异常处理
当执行任务时发生异常,那么该怎么处理呢?
首先看当Thread线程异常如何处理。在任务中通过try…catch是可以捕获异常并进行处理的,如下代码:
execute与submit的区别
执行任务除了可以使用execute方法还可以使用submit方法。它们的主要区别是:
execute适用于不需要关注返回值的场景。
submit方法适用于需要关注返回值的场景。
关闭线程池
关闭线程池可以调用shutdownNow和shutdown两个方法来实现。
shutdownNow:对正在执行的任务全部发出interrupt(),停止执行,对还未开始执行的任务全部取消,并且返回还没开始的任务列表。
shutdown:当我们调用shutdown后,线程池将不再接受新的任务,但也不会去强制终止已经提交或者正在执行中的任务。