线程饥饿死锁:
在线程池中,如果任务依赖于其他任务,那么可能产生死锁。
public class ThreadDeadlock {
ExecutorService executorService = Executors.newSingleThreadExecutor();
public class RenderPageTask implements Callable<String>{
@Override
public String call() throws Exception {
Future<String> header,footer;
header = executorService.submit(new LoadFile());
footer = executorService.submit(new LoadFile());
return header.get() + footer.get();
}
class LoadFile implements Callable<String>{
@Override
public String call() throws Exception {
return null;
}
}
}
}
运行时间较长的任务:
如果任务阻塞的时间过长,那么即使不出现死锁,线程池的响应性也会变得糟糕。
有一项技术可以缓解执行时间较长任务造成的影响,即是限定任务等待资源的时间,而不是无限制地等待。
设置线程池的大小:
分析计算环境、资源预算和任务的特征。在部署的系统中有多少个CPU?多大的内存?任务是计算密集型还是IO密集型还是两者都有?
对于计算密集型的任务,在拥有N个处理器的系统上,当线程池的大小为N+1时,通常能实现最优的利用率。
对于包含IO操作或者其他阻塞操作的任务,由于线程不会一直执行,因此线程池的规模应该更大。
ThreadPoolExecutor的构造函数:
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
线程的创建与销毁:
线程池的基本大小corePoolSize,最大大小maximumPoolSize以及存活时间keepAliveTime等因素共同负责线程的创建与销毁。
基本大小就是线程池的目标大小,即在没有任务执行时线程池的大小,并且只有在工作队列满了的情况下才会创建超出这个数量的线程。
最大大小表示可以同时活动的线程数量的上限。
存活时间:如果某个线程的空闲时间超过了存活时间,那么将线程标记为可回收的,并且当线程池的当前大小超过了基本大小时,这个线程将被终止。
当任务相互独立时,为线程池或者工作队列设置界限才是合理的,如果任务之间存在依赖性,那么有界的线程池或队列就可能导致线程饥饿死锁问题。此时应该使用无界的线程池,如newCachedThreadPool。
饱和策略
ThreadPoolExecutor的饱和策略可以通过setRejectedExecutionHandler来修改。
JDK提供了几种不同的RejectedExecutionHandler的实现,如AbortPolicy,CallerRunPolicy,DiscardPolicy,DiscardOldestPolicy。
终止Abort 策略是默认的饱和策略,该策略将抛出未检查的RejiectedExecutionException。
调用者运行Caller-Runs策略实现了一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量。
ThreadPoolExecutor executor = new ThreadPoolExecutor
(10, 100, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10));
//调用者允许实现饱和策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
抛弃策略Discard会悄悄抛弃该任务
抛弃最旧的Discard-Oldest策略会抛弃下一个将被执行的任务,然后尝试重新提交该任务。
线程工厂
每当线程池需要创建一个线程,都通过线程工厂方法来完成的。默认的线程工厂方法会创建一个新的、非守护的线程。
public interface ThreadFactory
{
public abstract Thread newThread(Runnable runnable);
}
自定义线程工厂:
public class MyThreadFactory implements ThreadFactory{
private final String poolName;
public MyThreadFactory(String poolName) {
super();
this.poolName = poolName;
}
@Override
public Thread newThread(Runnable runnable) {
return new MyAppThread(runnable,poolName);
}
}
public class MyAppThread extends Thread{
public static final String DEFAULT_NAME = "MyAppThread";
private static volatile boolean debugLifeCycle = false;
private static final AtomicInteger created = new AtomicInteger();
private static final AtomicInteger alive = new AtomicInteger();
private static final Logger LOGGER = Logger.getAnonymousLogger();
public MyAppThread(Runnable r){
this(r,DEFAULT_NAME);
}
public MyAppThread(Runnable runnable,String name){
super(runnable,name+"-"+created.incrementAndGet());
setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread thread, Throwable throwable) {
LOGGER.log(Level.SEVERE, "UNCAUGT in thread "+thread.getName(), throwable);
}
});
}
public void run(){
boolean debug = debugLifeCycle;
if(debug){
LOGGER.log(Level.FINE, "Created" + getName());
}
try {
alive.incrementAndGet();
super.run();
} finally {
alive.decrementAndGet();
if(debug){
LOGGER.log(Level.FINE, "Exiting "+getName());
}
}
}
public static int getThreadsCreated(){
return created.get();
}
public static int getThreadsAlive(){
return alive.get();
}
public static boolean getDebug(){
return debugLifeCycle;
}
public static void setDebug(boolean b){
debugLifeCycle = b;
}
}
扩展ThreadPoolExecutor
public class TimingThreadPool extends ThreadPoolExecutor{
public TimingThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
private final ThreadLocal<Long> startTime = new ThreadLocal<>();
private final Logger log = Logger.getLogger("TimingThreadPool");
private final AtomicLong numTasks = new AtomicLong();
private final AtomicLong totalTime = new AtomicLong();
protected void beforeExecute(Thread t,Runnable r){
super.beforeExecute(t, r);
log.fine("before");
startTime.set(System.nanoTime());
}
protected void afterExecute(Runnable r,Throwable t){
try {
long endTime = System.nanoTime();
long taskTime = endTime - startTime.get();
numTasks.incrementAndGet();
totalTime.addAndGet(taskTime);
log.fine("after");
} finally {
super.afterExecute(r, t);
}
}
protected void terminated(){
try {
log.fine("terminate");
} finally {
super.terminated();
}
}
}