/** * Initiates an orderly shutdown in which previously submitted * tasks are executed, but no new tasks will be accepted. * Invocation has no additional effect if already shut down. * * <p>This method does not wait for previously submitted tasks to * complete execution. Use {@link #awaitTermination awaitTermination} * to do that. * * @throws SecurityException if a security manager exists and * shutting down this ExecutorService may manipulate * threads that the caller is not permitted to modify * because it does not hold {@link * java.lang.RuntimePermission}{@code ("modifyThread")}, * or the security manager's {@code checkAccess} method * denies access. */ voidshutdown();
Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task com.java.interview.pool.ThreadPoolDemo$Task@5e5792a0 rejected from java.util.concurrent.ThreadPoolExecutor@26653222[Shutting down, pool size = 1, active threads = 1, queued tasks = 4, completed tasks = 0] at java.base/java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2055) at java.base/java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:825) at java.base/java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1355) at java.base/java.util.concurrent.Executors$DelegatedExecutorService.execute(Executors.java:687) at com.java.interview.pool.ThreadPoolDemo.shutdownTest(ThreadPoolDemo.java:23) at com.java.interview.pool.ThreadPoolDemo.main(ThreadPoolDemo.java:15)
/** * Attempts to stop all actively executing tasks, halts the * processing of waiting tasks, and returns a list of the tasks * that were awaiting execution. * * <p>This method does not wait for actively executing tasks to * terminate. Use {@link #awaitTermination awaitTermination} to * do that. * * <p>There are no guarantees beyond best-effort attempts to stop * processing actively executing tasks. For example, typical * implementations will cancel via {@link Thread#interrupt}, so any * task that fails to respond to interrupts may never terminate. * * @return list of tasks that never commenced execution * @throws SecurityException if a security manager exists and * shutting down this ExecutorService may manipulate * threads that the caller is not permitted to modify * because it does not hold {@link * java.lang.RuntimePermission}{@code ("modifyThread")}, * or the security manager's {@code checkAccess} method * denies access. */ List<Runnable> shutdownNow();
java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at java.base/java.lang.Thread.sleep(Thread.java:339) at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446) at com.java.interview.pool.ThreadPoolDemo$Task.run(ThreadPoolDemo.java:73) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)
/** * Blocks until all tasks have completed execution after a shutdown * request, or the timeout occurs, or the current thread is * interrupted, whichever happens first. * * @param timeout the maximum time to wait * @param unit the time unit of the timeout argument * @return {@code true} if this executor terminated and * {@code false} if the timeout elapsed before termination * @throws InterruptedException if interrupted while waiting */ booleanawaitTermination(long timeout, TimeUnit unit)throws InterruptedException;
java.lang.InterruptedException: sleep interrupted at java.base/java.lang.Thread.sleep(Native Method) at java.base/java.lang.Thread.sleep(Thread.java:339) at java.base/java.util.concurrent.TimeUnit.sleep(TimeUnit.java:446) at com.java.interview.pool.ThreadPoolDemo$Task.run(ThreadPoolDemo.java:146) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)
第 10 次提交 rejected, task-10 is pool stoped: true ----------------- main all tests finished
/** * 调用 execute() 方法提交任务,默认会抛出异常 */ privatestaticvoidexecute(){ ExecutorService threadPool = Executors.newFixedThreadPool(2); try { // 调用 execute() 方法提交任务,会抛出异常 threadPool.execute(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "进入 execute() 方法 ---start"); for (int i = 1; i <= 4; i++) { if (i == 3) { int age = 10 / 0; } System.out.println("come in execute: " + i); } System.out.println(Thread.currentThread().getName() + "\t" + "进入 execute() 方法 ---end"); }); } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } }
}
程序执行的输出结果:
1 2 3 4 5 6 7 8
pool-1-thread-1 进入 execute() 方法 ---start come in execute: 1 come in execute: 2 Exception in thread "pool-1-thread-1" java.lang.ArithmeticException: / by zero at com.java.interview.pool.ThreadPoolDemo.lambda$execute$0(ThreadPoolDemo.java:29) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)
pool-1-thread-1 进入 submit() 方法 ---start java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191) at com.java.interview.pool.ThreadPoolDemo.submitAndGet(ThreadPoolDemo.java:55) at com.java.interview.pool.ThreadPoolDemo.main(ThreadPoolDemo.java:14) Caused by: java.lang.ArithmeticException: / by zero at com.java.interview.pool.ThreadPoolDemo.lambda$submitAndGet$1(ThreadPoolDemo.java:51) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834)
/** * Method invoked upon completion of execution of the given Runnable. * This method is invoked by the thread that executed the task. If * non-null, the Throwable is the uncaught {@code RuntimeException} * or {@code Error} that caused execution to terminate abruptly. * * <p>This implementation does nothing, but may be customized in * subclasses. Note: To properly nest multiple overridings, subclasses * should generally invoke {@code super.afterExecute} at the * beginning of this method. * * <p><b>Note:</b> When actions are enclosed in tasks (such as * {@link FutureTask}) either explicitly or via methods such as * {@code submit}, these task objects catch and maintain * computational exceptions, and so they do not cause abrupt * termination, and the internal exceptions are <em>not</em> * passed to this method. If you would like to trap both kinds of * failures in this method, you can further probe for such cases, * as in this sample subclass that prints either the direct cause * or the underlying exception if a task has been aborted: * * <pre> {@code * class ExtendedExecutor extends ThreadPoolExecutor { * // ... * protected void afterExecute(Runnable r, Throwable t) { * super.afterExecute(r, t); * if (t == null * && r instanceof Future<?> * && ((Future<?>)r).isDone()) { * try { * Object result = ((Future<?>) r).get(); * } catch (CancellationException ce) { * t = ce; * } catch (ExecutionException ee) { * t = ee.getCause(); * } catch (InterruptedException ie) { * // ignore/reset * Thread.currentThread().interrupt(); * } * } * if (t != null) * System.out.println(t); * } * }}</pre> * * @param r the runnable that has completed * @param t the exception that caused termination, or null if * execution completed normally */ protectedvoidafterExecute(Runnable r, Throwable t){ }
publicstaticvoidmain(String[] args){ // 手动创建线程池 ExecutorService threadPool = createThreadPool(); try { // 调用 submit() 方法提交任务,默认会吞掉异常,改写后可以抛出异常了 threadPool.submit(() -> { System.out.println(Thread.currentThread().getName() + "\t" + "进入 submit() 方法 ---start"); for (int i = 1; i <= 4; i++) { if (i == 3) { int age = 10 / 0; } System.out.println("come in execute: " + i); } System.out.println(Thread.currentThread().getName() + "\t" + "进入 submit() 方法 ---end"); }); } catch (Exception e) { e.printStackTrace(); } finally { threadPool.shutdown(); } }
......
}
程序执行的输出结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
pool-1-thread-1 进入 submit() 方法 ---start come in execute: 1 come in execute: 2 16:11:12.103 [pool-1-thread-1] ERROR com.java.interview.pool.ThreadPoolDemo - java.lang.ArithmeticException: / by zero java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191) at com.java.interview.pool.ThreadPoolDemo$1.afterExecute(ThreadPoolDemo.java:113) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1129) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: java.lang.ArithmeticException: / by zero at com.java.interview.pool.ThreadPoolDemo.lambda$test02$1(ThreadPoolDemo.java:55) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ... 2 common frames omitted
线程池如何合理配置参数
重点面试题
生产环境中如何配置线程池的 corePoolSize 和 maximumPoolSize 参数?
首先需要弄清楚一点,业务系统是属于 CPU 密集型还是 I/O 密集型的。因为线程池的配置,是需要根据具体不同的业务来配置。
CPU 密集型
CPU 密集的意思是,该任务需要大量的运算,而且没有阻塞,CPU 一直全速运行
CPU 密集任务只有在真正的多核 CPU 上才可能得到加速执行(使用多线程),而在单核 CPU 上,无论启动几个模拟的多线程,该任务都不可能得到加速执行
CPU 密集型的任务,应该尽可能少的配置线程数量
一般配置公式:CPU 核心数 + 1 个线程数
I/O 密集型
IO 密集型的意思是,该任务需要大量的 I/O 操作(网络、磁盘等),大部分线程都会被阻塞
由于 I/O 密集型的任务线程并不是一直在执行任务,因此需要尽可能多配置线程数,如 CPU 核心数 * 2
在单线程上执行 I/O 密集型的任务,会浪费大量的 CPU 运算能力,即花费大量时间在阻塞等待上;所以在 I/O 密集型任务中,使用多线程可以大大的加速程序的运行,这种加速主要就是利用了被浪费掉的阻塞时间