首页 > 代码库 > 《Java并发编程实战》第八章 线程池的使用 读书笔记

《Java并发编程实战》第八章 线程池的使用 读书笔记


一、在任务与执行策略之间的隐性解耦

有些类型的任务需要明确地指定执行策略,包括:
. 依赖性任务。依赖关系对执行策略造成约束,需要注意活跃性问题。要求线程池足够大,确保任务都能放入。
. 使用线程封闭机制的任务。需要串行执行。
. 对响应时间敏感的任务。
. 使用ThreadLocal的任务。

1. 线程饥饿死锁
线程池中如果所有正在执行任务的线程都由于等待其他仍处于工作队列中的任务而阻塞,这种现象称为线程饥饿死锁。

2. 运行时间较长的任务
Java提供了限时版本与无限时版本。例如Thread.join、BlockingQueue.put、CutDownLatch.await、Selector.select

二、设置线程池的大小

要正确地设置线程池的大小,你必须估算出任务的等待时间与计算时间的比值。这种估算不需要很精确,并且可以通过一些分析或监控工具来获得。
公式定义:
int N_CPUS = Runtime.getRuntime().availableProcessors();
CPU并不是唯一影响线程池大小的资源,还包括内存、文件句柄、套接字句柄和数据库连接等。计算每个任务对该资源的需求量,然后用该资源的可用总量除以每个任务的需求量,所得结果就是线程池大小的上限。

三、配置ThreadPoolExecutor


API文档中对构造函数的描述:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          RejectedExecutionHandler handler)
用给定的初始参数和默认的线程工厂创建新的 ThreadPoolExecutor。


1. 线程池的创建与销毁
可以查看Executors几个方法源码来辅助理解ThreadPoolExecutor参数的配置。

2. 管理队列任务
ThreadPoolExecutor允许提供一个BlockingQueue来保存等待执行的任务。基本的任务排队方法有3种:无界队列、有界队列、同步移交。

java.util.concurrent.BlockingQueue 所有已知实现类: 
ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue
 
3. 饱和策略
有界队列已经填满或者向关闭的Executor提交任务时需要考虑饱和策略。
ThreadPoolExecutor.setRejectedExecutionHandler
public void setRejectedExecutionHandler(RejectedExecutionHandler handler)设置用于未执行任务的新处理程序。 

java.util.concurrent.RejectedExecutionHandler 所有已知实现类: 
ThreadPoolExecutor.AbortPolicy, ThreadPoolExecutor.CallerRunsPolicy, ThreadPoolExecutor.DiscardOldestPolicy, ThreadPoolExecutor.DiscardPolicy 

AbortPolicy是默认饱和策略
-- 待填充

4. 工厂方法

5. 在调用构造函数后再定制ThreadPoolExecutor
在创建线程池后,依然可以通过ThreadPoolExecutor提供的方法修改构造时传入的参数。

四、扩展ThreadPoolExecutor
五、递归算法的并行化

暂时用不到