在任务与执行策略之间的隐形耦合
不是所有的任务都适合直接将其甩给线程池进行执行,然后可以随意的更改线程池的配置,只影响效率,而不影响其他。如以下任务:
依赖性任务
任务并不是完全独立的,而是要依赖其他任务的执行结果
使用线程封闭机制的任务
任务只能在单线的线程池中运行,从而保证任务的线程安全
对响应时间敏感的任务
将一个长时间任务甩给一个线程数量不多的线程池,将会导致某些任务长时间等待,如果是gui程序,将严重影响其响应时间
使用ThreadLocal的任务
使用ThreadLocal来封闭线程的变量副本确保变量的线程安全
线程饥饿死锁
一个任务A提交另外一个任务B到同样的Executor中,如果线程池数量不够大,则有可能形成A等待B执行完成,而B在等待A执行完成,从而形成饥饿死锁。
运行时间较长的任务
当线程池中所有任务都去执行运行时间较长的任务时,从而影响整体的性能。
设置线程池大小
对于计算密集性任务,当线程池大小为Ncpu+1时,通常能实现最优利用率。对于包含IO密集型的任务,还可以将线程池的规模扩展至更大。
配置ThreadPoolExecutor
线程池的创建与销毁
通过线程池的参数 corePoolSize(基本大小),maximumPoolSize(最大大小)、keepAliveTime(空闲存活时间)属性来确定线程池。当线程队里满了之后,会产生超出线程池基本大小的线程。
管理队列任务
newFixedThreadPool和newSingleThreadPool使用LinkedBlockingQueue的无界队列。newCachedThreadPool使用一种假队列,直接将任务移交给线程。
饱和策略
中止:抛异常
抛弃:悄悄抛弃任务
抛弃最旧的:抛弃旧任务
调用者运行:将任务退回给调用线程,让调用线程的主线程执行任务,如果任务量过大,则一路阻塞,从线程池到工作队列到应用程序再到TCP层,最终到达客户端,从而实现性能的平滑下降。
线程工厂
在调用构造函数后再定制ThreadPoolExecutor
见名知意,其他的暂时没有什么好说的。
扩展ThreadPoolExecutor
通过继承ThreadPoolExecutor线程池,重写beforeExecutor、afterExecutor、terminated方法,来增强线程池实现自己的线程池功能。
递归算法的并行化