线程饥饿死锁:
在线程池中,如果任务依赖于其他任务,那么可能产生死锁。
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(); } } }