线程池
线程池ThreadPoolExecutor继承关系

创建的关键参数及含义
- corePoolSize:线程池中核心线程数,即使是闲置的也会存在,除非
allowCoreThreadTimeOut被设置为true(需配合keepAliveTime>0使用) - maximumPoolSize:线程池中允许的最大线程数。
FixedThreadPool同corePoolSize,cachedThreadPool为Integer.MAX_VALUE,SingleThread为1 - keepAliveTime:非核心线程闲置后允许存活的时间,一般为0。如果
allowCoreThreadTimeOut为true,闲置核心线程也会被销毁 - unit:keepAliveTime的时间单位,一般为毫秒
TimeUnit.MILLISECONDS - workQueue:任务队列。task被提交后未执行时保存所在的队列,类型为阻塞队列
BlockingQueue,一般为LinkedBlockingQueue或ArrayBlockingQueue。- 当小于
corePoolSize的线程在执行时,task不会入队,而是创建一个新核心线程执行 - 当等于
corePoolSize的核心线程在执行并且队列非满时,task会入队 - 当等于
corePoolSize的核心线程在执行并且队列满并且正在执行的总线程不大于maximumPoolSize时,会创建一个新非核心线程执行 - 当队列满并且当前执行的总线程达到
maximumPoolSize时,会根据rejectedExecutionHandler执行拒绝策略。
- 当小于
- threadFactory:创建新线程的工厂类。一般使用默认的工厂类
Executors.defaultThreadFactory() - rejectedExecutionHandler:当任务队列满时的拒绝策略。下为
ThreadPoolExecutor中默认的四种拒绝策略。- DiscardPolicy():直接拒绝,不抛出异常
- DiscardOldestPolicy():丢弃任务队列队首任务(等待时间最长的任务),将新任务加入。
- AbortPolicy():直接拒绝,抛出
RejectedExecutionException异常(默认) - CallerRunsPolicy():如果当前线程池没有关闭,将新任务在调用所在线程直接执行(直接调用r.run())而不是线程池调度.
线程池的种类及作用
-
newFixedThreadPool:创建容纳固定线程数的线程池,适用大负载的服务器
public class Executors { public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } } -
newCachedThreadPool:创建可容纳Integer.MAX_VALUE大小的线程池,空闲线程的存货时间为60秒,提交新任务时,不会排成队列(SynchronousQueue)而是创建新的线程执行。适用小负载的服务器,避免直接使用此方法,因为其
maximumPoolSize过大public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); } -
newSingleThreadExecutor:与fixedThreadPool相似,创建只能容纳一个线程的线程池
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } -
ScheduledExecutorService:创建一个可以延后一段时间或定期执行任务的线程池
// Executors public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); } // ScheduledThreadPoolExecutor public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS, //10秒 new DelayedWorkQueue()); } -
newWorkStealingPool(属于ForkJoinPool):大任务拆分(fork)成小任务,并行执行,合并(join)小任务结果。参考线程池ForkJoinPool简介
submit和execute方法有什么区别
-
submit是
AbstractExecutorService的方法,而execute是顶层接口Executor的方法,由ThreadPoolExecutor实现。 -
submit可以接收
Callable和Runnable类型的参数,execute只能接收Runnable类型的参数。submit方法内部也会调用execute方法,不过AbstractExecutorService自己没有实现而是交给ThreadPoolExecutor实现,AbstractExecutorService在调用execute前后做了一系列封装,使得submit能够接收Callable或Runnable参数并返回Future。 -
submit如果线程抛出异常会将异常暂存不会立即抛出,等到调用get()方法时才抛出,execute线程发生异常会立即抛出
public class Example { public static void diffSubmitAndExecute() throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(6); // execute会立即抛出 executor.execute(() -> {throw new IllegalStateException("execute手动异常");}); // submit在submit时不会立即抛出,而是调用get时抛出 Future<String> res = executor.submit(() -> { throw new IllegalStateException("submit手动异常"); }); // 抛出异常 Object o = res.get(); } }
170万+

被折叠的 条评论
为什么被折叠?



