7.多线程--线程池的使用
一.在任务与执行策略之间的隐性耦合
1.线程饥饿死锁
在线程池中,如果任务依赖于其他任务,那么可能产生死锁。在单线程的Executor中,如果一个任务将另一个任务提交到同一个Executor,并且等待这个被提交任务的结果,那么通常会引发死锁。第二个任务停留在工作队列中,并等待第一个任务完成,而第一个任务又无法完成,因为它在等待第二个任务的完成。在更大的线程池中,如果所有正在执行任务的线程都由于等待其他仍处于工作队列中的任务而阻塞,那么会发生同样的问题。这种现象被称为线程饥饿死锁(Thread Starvation Deadlock)。
public class ThreadDeadlock { ExecutorService exec = Executors.newSingleThreadExecutor(); public class LoadFileTask implements Callable<String> { private final String fileName; public LoadFileTask(String fileName) { this.fileName = fileName; } public String call() throws Exception { // Here's where we would actually read the file return ""; } } public class RenderPageTask implements Callable<String> { public String call() throws Exception { Future<String> header, footer; header = exec.submit(new LoadFileTask("header.html")); footer = exec.submit(new LoadFileTask("footer.html")); String page = renderBody(); // Will deadlock -- task waiting for result of subtask return header.get() + page + footer.get(); } private String renderBody() { // Here's where we would actually render the page return ""; } } }
2.运行时间较长的任务
二.设置线程池大小
三.配置ThreadPoolExecutor
1.线程的创建与销毁
2.管理队列任务
3.饱和策略
当有界队列被填满后,饱和策略开始发挥作用。JDK提供了几种不同的RejectedExecutionHandler实现,每种实现都 包含有不同的饱和策略: AbortPolicy、 CallerRunsPolicy、 DiscardPolicy 和DiscardOldestPolicy. 包含有不同的饱和策略:AbortPolicy、CallerRunsPolicy、DishardPolicy和DishardOldestPolicy。
中止(Abort)策略是默认的饱和策略,该策略将抛出未检查的RejectedExecution- Exception。
“调用者运行( Caller-Runs)”策略实现了一种调节机制,该策略既不会拋弃任务,也不 会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。
4.线程工厂
5.在调用构造函数后再定制ThreadPoolExecutor
四.扩展ThreadPoolExecutor