本文共 4077 字,大约阅读时间需要 13 分钟。
submit方法(三个重载方法)
invokeAny和invokeAll方法
两阶段shutdown
void shutdownAndAwaitTermination(ExecutorService pool) { pool.shutdown(); // Disable new tasks from being submitted try { // Wait a while for existing tasks to terminate if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { pool.shutdownNow(); // Cancel currently executing tasks // Wait a while for tasks to respond to being cancelled if (!pool.awaitTermination(60, TimeUnit.SECONDS)) System.err.println("Pool did not terminate"); } } catch (InterruptedException ie) { // (Re-)Cancel if current thread also interrupted pool.shutdownNow(); // Preserve interrupt status Thread.currentThread().interrupt(); }}
interrupt方法
如果执行a.interrupt方法后,如果a线程(注意是a线程,不是调用线程)抛出了InterruptedException异常,那么a的中断状态会被清除。如果不是抛出InterruptedException异常,那么a的中断状态都会被设置。
interrupted方法
执行a.interrupted方法会返回a线程的中断状态,同时会清除a线程的中断状态
isInterrupted方法
执行a.interrupted方法会返回a线程的中断状态,不会清除a线程的中断状态
一个新的任务提交哪些情况下回创建新的线程: 1. 已创建的的线程数小于corePoolSize(即便有线程是空闲的) 2. 已创建的线程数大于corePoolSize小于maxPoolSize,同时任务队列已经满的情况下,也会创建新的线程可以动态改变这两个的值:setCorePoolSize 以及 setMaximumPoolSize如果corePoolSize==maxinumPoolSize,那么则创建了一个固定大小的线程池
如果已创建的线程大于了corePoolSize,并且如果有线程的空闲时间大于了keepAliveTime,那么这些线程会被kill掉直到剩下corePoolSize个线程。可以动态设置:setKeepAliveTime方法默认情况下keep-alive策略只会针对已创建线程数大于corePoolSize的情况下可以通过执行allowCoreThreadTimeOut(boolean)让keep-alive策略应用在已创建线程数小于corePoolSize的情况下。
1. 如果已创建线程数小于corePoolSize,那么会创建新的线程来执行当前提交的任务,而不是进入阻塞队列2. 如果已创建线程数大于等于corePoolSize,会尝试先进入阻塞队列,如果进入失败(其实就是队列已满),则会在maxPoolSize条件下创建新的线程来执行当前提交的任务。如果不满足maxPoolSize条件,那么就会执行 拒绝执行策略(默认的拒绝执行策略见下)3. 通常有三种入队列策略 1. 直接传递给线程(Direct handoffs)
比如:SychronousQueue感觉可以理解为这个入队列会总是失败,就相当于没有这个队列一样。这样就能在maxPoolSize条件下尽可能快的创建(或选择空闲的线程)来执行新提交的任务。如果提交的任务有互相的依赖性,可以考虑使用这种队列。public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue());}
2. 无界队列(Unbounded Queue)
比如:LinkedBlockingQueue可以理解为如果有任务需要入队列,那么总会入队成功。因此按照创建新线程的条件,理论上不会有超过corePoolSize个数的线程。也就是说理论上线程数最多为corePoolSize,因此maxPoolSize的设置也就显得没有意义了。如果提交的任务互相间没有依赖性,可以考虑使用这种队列
3. 有界队列(Bounded Queue)
比如:ArrayBlockingQueue如果使用有限个maxPoolSize,那么使用这种队列可以防止资源的耗尽。使用长队列和小的线程池,可以降低CPU使用率,降低系统资源的消耗,以及降低线程上下文切换的消耗,但是会导致低吞吐量。如果任务频繁的阻塞,系统可能会创建比允许的线程数多的线程。使用短队列和大的线程池,可以提高CPU使用率,但也有可能导致吞吐量下降。
我自己的叫法,实际上就是 RejectedExceptionHandler
1. ThreadPoolExecutor.AbortPolicy 抛出RejectedExecutionException异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());}
2. ThreadPoolExecutor.CallerRunsPolicy 在调用线程上执行(哪个线程提交的任务就哪个线程执行)
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); }}
3. ThreadPoolExecutor.DiscardPolicy 直接放弃
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {}
4. ThreadPoolExecutor.DiscardOldestPolicy 放弃当前队列中第一个任务
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); }}
一个在程序中不再被引用的线程池如果同时没有剩余的线程,那么这个线程池会被自动的shutdown.
因此如果你想即便在忘记执行shutdown方法的时候仍能正常关闭线程池,
那么建议设置一个有限的keepAliveTime(针对大于线程数大于corePoolSize的那些线程),同时也执行下 allowCoreThreadTimeOut(boolean) .欢迎关注公众号