8.1在任务与执行策略之间的印象耦合
1.依赖性任务
2.使用线程封闭机制的任务
3.对响应时间敏感的任务
4.使用ThreadLocal的任务
线程池
8.1.1线程饥饿死锁
程序清单8-1 在单线程Executor中任务发生死锁(不要这么做)
/**
* 线程饥饿死锁(Thread Starvation Deadlock)
* RenderPageTask本身还没执行完呢,是不会让出唯一的一个线程给header和footer,
* 因为RenderPageTask依赖于header和footer的执行结果。
*/
public class ThreadDeadLock {
ExecutorService exec = Executors.newSingleThreadExecutor(); //单线程的线程池
public class RenderPageTask implements Callable { //提交Callable
public String call() throws Exception {
Future header,footer;
//RenderPageTask的Callable任务将另外2个任务提交到了同一个Executor中,并且等待这个被提交任务的结果
header = exec.submit(new LoadFileTask("header.html")); //Callable中嵌套的线程启用
footer = exec.submit(new LoadFileTask("footer.html")); //Callable中嵌套的线程启用
String page = renderBody();
//将发生死锁 —— 由于任务在等待子任务的结果
return header.get() + page + footer.get();
}
}
}
8.1.2 运行时间较长的任务
8.1.3 设置线程池的大小
int N_CPU = Runtime.getRuntime().availableProcessors();
计算密集型:N个CPU的处理器的系统上,线程池大小通常为N+1 最优
8.3 配置ThreadPoolExecutor
ThreadPoolExecutor源码解析
@Data //可以通过getter、setter定制线程池
public class ThreadPoolExecutor extends AbstractExecutorService {
private final BlockingQueue workQueue; //getter、setter
private final HashSet workers = new HashSet();//getter、setter
private final Condition termination = mainLock.newCondition();//getter、setter
private int largestPoolSize; //getter、setter
private long completedTaskCount; //getter、setter
//线程工厂,线程池里的线程都是通过这个工厂创建的
private volatile ThreadFactory threadFactory; //getter、setter
//饱和策略,默认是“中止策略”:AbortPolicy
private volatile RejectedExecutionHandler handler; //getter、setter
private static final RejectedExecutionHandler defaultHandler =new AbortPolicy();
private volatile long keepAliveTime; //getter、setter
private volatile boolean allowCoreThreadTimeOut; //getter、setter
private volatile int corePoolSize; //getter、setter
private volatile int maximumPoolSize; //getter、setter
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory and rejected execution handler.
* It may be more convenient to use one of the {@link Executors} factory
* methods instead of this general purpose constructor.
* 线程池中保持的线程数,即便线程是闲置的,除非allowCoreThreadTimeOut被设置
* 只有在工作队列满了的情况下,才会创建超出这个数量的线程
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* 可同时活动的线程数量上限
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* 如果某个线程的空闲时间超过了keepAliveTime,那么将被标记为可回收的,
* 并且当线程池的大小超过了基本大小时,这个空闲的线程将被终止。
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* 时间单位
* @param unit the time unit for the {@code keepAliveTime} argument
* //阻塞式工作队列
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @throws IllegalArgumentException if one of the following holds:
* {@code corePoolSize < 0}
* {@code keepAliveTime < 0}
* {@code maximumPoolSize <= 0}
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue} is null
*/
/**构造方法1,全自定义*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) { }
/**构造方法2 调用了构造方法1,使用默认【线程工厂】,自定义的饱和策略*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);}
/**构造方法3 调用构造方法2,使用默认的【饱和策略】和默认的【线程工厂】*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
//8.4 拓展ThreadPoolExecutor
//自定义➕日志如果此处抛出一个异常,那么任务不会被调用,afterExecute也不会被调用
protected void beforeExecute(Thread t, Runnable r) { }
//无论是从run中返回还是抛出一个异常返回,afterExecute都会被调用,(如果带有一个Error则不调用)
protected void afterExecute(Runnable r, Throwable t) { }
//线程池完成关闭操作时调用此方法,也就是在所有任务都已经完成并且所有工作者线程都已经关闭后
//可以用来释放Executor在其生命周期里分配的各种资源,此外还可以执行发生通知、
//记录日志或收集finalize统计信息等操作
protected void terminated() { }
/**
* 当队列被填满后,新提交的任务无法保存到队列中等待执行时,抛弃策略开始起作用
*/
/**
* 调用者-运行策略,实现了一种调节机制,改策略不会抛弃任务,也不会抛出异常
* 而是将某些任务回退到调用者,从而降低新任务流量。他不会再线程池的某个线程中执行新提交的任务,
* 而是在一个调用了Executor.execute()的线程中执行该任务。
*
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run(); //没有在线程池中启用线程,run()方法直接调用,在ThreadPoolExecutor的调用者线程中执行
}
}
//
}
//终止饱和策略,抛出异常,让用户自己处理, 默认的
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
/** 参数信息同上
* Always throws RejectedExecutionException.
* @throws RejectedExecutionException always
*/
throw new RejectedExecutionException("Task " + r.toString() +" rejected from " +e.toString());
}
//抛弃策略,啥也不干,discarding task r.
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
/**参数信息同上
* Does nothing, which has the effect of discarding task r.
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {} //Does noting
}
/**
* 如果工作队列是一个优先队列,“抛弃最旧的策略”将导致抛弃优先级最高的任务,
* 因此不要将优先队列和DiscardOldestPolicy放在一起使用
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
/**参数信息同上*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();//抛弃下一个将被执行的任务,
e.execute(r);//尝试在线程池中重新提交新的任务
}
}
}
}
程序清单8-5 线程工程接口
package java.util.concurrent;
public interface ThreadFactory {
Thread newThread(Runnable r);
}
程序清单8-6 自定义线程工厂
import java.util.concurrent.ThreadFactory;
public class MyThreadFactory implements ThreadFactory {
private final String poolName;
public MyThreadFactory(String poolName) {
this.poolName = poolName;
}
@Override
public Thread newThread(Runnable r) {
return new MyThread(r,poolName);
}
}
//自定义线程
class MyThread extends Thread {
MyThread(Runnable r,String name) { }
}
Executors工具类中定义的静态线程工厂类:
DefaultThreadFactory 和 PrivilegedThreadFactory
Executors.defaultThreadFactory(); //获取默认的线程工厂类实例创建线程
Executors.privilegedThreadFactory() ;//获取优先级的线程工厂类实例创建线程
详见下方的源码解析:
Executors源码解析
public class Executors {
/**
* 默认线程池的有界LinkedBlockingQueue,
* 基本大小(corePoolSize)和最大大小(maxinumPoolSize)同为参数大小
* keepAliveTime=0,代表不会超时,永远都在
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool(parallelism, ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true);
}
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true);
}
/**
* 默认线程池的有界LinkedBlockingQueue,
* 基本大小(corePoolSize)和最大大小(maxinumPoolSize)同为参数大小
* keepAliveTime=0,代表不会超时,永远都存活
*/
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(), threadFactory);
}
/**
* 本类中自定义的FinalizableDelegatedExecutorService封装ThreadPoolExecutor,
* 返回类型为ExecutorService,只暴露ExecutorService的接口,因此不能对它配置
*
* 基本线程数量和最大线程数量都是1,keepAliveTime=0,线程永远不超时,不会被回收
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(
new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()));
}
/**
* 本类中自定义的FinalizableDelegatedExecutorService封装ThreadPoolExecutor,
* 返回类型为ExecutorService,只暴露ExecutorService的接口,因此不能对它配置
*
* 基本线程数量和最大线程数量都是1,keepAliveTime=0,线程永远不超时,不会被回收
*/
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(), threadFactory));
}
/**
* 基本大小设置为0,最大大小是最大的合法整数,并将超时时间设置为1分钟。
* 所以这种方法创建出来的线程池可以被无限扩展,并且当需求降低时可以自动收缩。
* @return
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue());
}
/**
* 基本大小设置为0,最大大小是最大的合法整数,并将超时时间设置为1分钟。
* 所以这种方法创建出来的线程池可以被无限扩展,并且当需求降低时可以自动收缩。
* @return
*/
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue(),
threadFactory);
}
/**------------带有日程安排的线程池的创建----------*/
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, threadFactory));
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
if (executor == null)
throw new NullPointerException();
return new DelegatedExecutorService(executor);
}
public static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
if (executor == null)
throw new NullPointerException();
return new DelegatedScheduledExecutorService(executor);
}
/**------------带有日程安排的线程池的创建----------*/
/**获取默认的线程工厂*/
public static ThreadFactory defaultThreadFactory() {
return new DefaultThreadFactory();
}
/**获取具有 优先级的线程工厂*/
public static ThreadFactory privilegedThreadFactory() {
return new PrivilegedThreadFactory();
}
public static Callable callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter(task, result);
}
public static Callable
对于非常大的或者无界的线程池,可以通过使用SynchronousQueue来避免任务排队,以 及直接将任务从生产者移交给工作者线程.SynchronousQueue不是一个真正的队列,而是一 种在线程之间进行移交的机制.要将一个元素放入SynchronousQueue中,必须有另一个线程 正在等待接受这个元素。如果没有线程正在等待,并且线程池的当前大小小于最大值,那么 ThreadPoolExecutor将创建一个新的线程,否则根据饱和策略,这个任务将被拒绝。使用直接移将更高效,因为任务会直接移交给执行它的线程,而不是被首先放在队列中,然后由工作 者线程从队列中提取该任务•只有当线程池是无界的或者可以拒绝任务时,SynchronousQueue 才有实际价值•在ncwCachedThreadPool工厂方法中就使用了 SynchronousQueue。
Listing 8.17. Resultbearing Latch Used by ConcurrentPuzzleSolver.
@ThreadSafe
public class ValueLatch {
@GuardedBy("this") private T value = null;
private final CountDownLatch done = new CountDownLatch(1);
public boolean isSet() {
return (done.getCount() == 0);
}
public synchronized void setValue(T newValue) {
if (!isSet()) {
value = newValue;
done.countDown();
}
}
public T getValue() throws InterruptedException {
done.await();
synchronized (this) {
return value;
}
}
}