basic
-
Java里的是线程(不是进程),Java线程直接映射到操作系统的线程,1:1的关系。会受到操作系统的线程调度、线程数量限制的影响
-
为什么用线程池:线程的创建和销毁开销非常高(时间、内存)
-
线程池越大越好?
线程消耗系统资源,尤其是内存,如果有大量闲置线程会占用很多内存;而且还会竞争CPU时间
当系统负载变高,程序仍然认为自己能处理,创建很多线程,结果崩溃(任务过多导致OOM或者系统限制)
Java线程池
Java线程池很常用的类:ThreadPoolExecutor,下面是参数最全的构造方法,其他的构造方法最终也是调用的这个
构造方法的参数的含义
-
corePoolSize 核心线程数,即使空闲也会存在于线程池里
-
maximumPoolSize 线程池中允许的线程数量最大值
-
keepAliveTime 线程池中线程数多于corePoolSize时,空闲线程的最大等待时间
-
unit
-
workQueue 待执行的任务队列。JDK提供的四种实现如下:
- ArrayBlockingQueue:基于数组结构的有界阻塞队列,FIFO
- LinkedBlockingQueue:基于链表结构的阻塞队列
- SynchronousQueue:不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态
- PriorityBlockingQueue:有优先级的无限阻塞队列
-
threadFactory 用于线程池的线程创建。可以使用默认的,也可以自己实现,指定线程的名称,方便查找问题
-
handler 当池中线程和任务队列都满了之后的抛弃策略。JDK提供的四种RejectedExecutionHandler实现如下:
-
AbortPolicy:直接抛出异常。默认策略
- CallerRunsPolicy:只用调用者所在线程来运行任务。
- DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
- DiscardPolicy:不处理,丢弃掉。
-
指定构造参数需要注意的地方
-
RejectedExecutionHandler需要自己指定
必须要自己实现该接口,加监控、日志。看需要抛异常 - 线程池参数的重新指定,除了workQueue之外,其余参数都可以再线程池运行中重新制定。
corePoolSize: 如果小于原值,多出来的线程会在下次空闲时终止;如果大于原值,会根据workQueue中的任务按需创建。线程的终结和创建都会立即尝试。
maximumPoolSize: 如果小于原值,多出来的线程会在下次空闲时终止(立即尝试)
keepAliveTime: 逻辑同上。 - workQueue的大小
线程池创建之后,workQueue就不能再重新设置,其大小不能发生变化。
当workQueue是无界队列时,maximumPoolSize无用 - maximumPoolSize > corePoolSize
创建时:。。
重新设置时:如果core和max都发生变化,需要先设置corePoolSize,再设置maximumPoolSize
提交任务的流程
- 如果当前线程数小于corePoolSize,尝试创建一个新的线程,并运行当前任务。成功则返回
- 尝试把任务添加到workQueue中,添加成功后再次检查是否需要创建Worker,以防当前无运行线程或者线程池停止了
- 如果任务添加到workQueu中失败,尝试创建新的线程。失败则reject()
Runnable, Callable, Future的关系
FutureTask实现了Runnable、Future接口,可以把Callable转为Runnable,同时在FutureTask.run()的实现里保存了Callable的结果或者异常
作为Runnable的实现,FutureTask可以提交到线程池中执行
作为Future的实现,FutureTask能检测任务的状态,终止任务,以及得到任务的结果
注意:Future.get(time, TimeUnit),这个方法指定的超时时间是从调用get()开始计算的,不是任务执行的时候
Guava相关
ListenableFuture:可以指定当前任务结束后的另一个任务
- public void addListener(Runnable listener, Executor executor);
- Futures#addCallback(ListenableFuture<V>, FutureCallback<? super V>) 可以在onSuccess和onFailure中处理结果或异常
ListeningExecutorService 继承自ExecutorService,没增加额外方法,所有的Future都变成了ListenableFuture
- MoreExecutors#listeningDecorator(ExecutorService) 可以把ExecutorService包装成ListeningExecutorService
Spring相关
-
可配置的线程池,ThreadPoolTaskExecutor
ThreadPoolTaskExecutor没有实现ExecutorService,submit()方法是通过AsyncTaskExecutor继承来的
-
@Async直接使方法变成异步(MDC??)
ThreadLocal
如果使用线程池,要注意有没有通过ThreadLocal传参数,特别是改写原有代码的时候
MDC
Logback实现的MDC(LogbackMDCAdapter)使用了ThreadLocal,使用了MDC要注意传递MDC的信息
MTracer
- MTrader.wrap()
- 如果是使用的Spring的AsyncTaskExecutor,可以用MTraceAsyncTaskExecutor