public class Task implements Runnable { private int no; private int size; public Task(int no, int size) { this.no = no; this.size = size; } @Override public void run() { try { System.out.println("执行中, Task: " + no + ", Thread: " + Thread.currentThread().getName() + ", queue.size: " + size); Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } }
public class Main { private static ExecutorService pool; public static void main(String[] args) { BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(8); pool = new ThreadPoolExecutor( 2, 5, 1000, TimeUnit.MILLISECONDS, queue, Executors.defaultThreadFactory(), new RejectedExecutionHandler() { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println("拒绝中, " + r.toString() + ", queue.size: " + queue.size()); } }); for (int i = 0; i < 15; i++) { pool.execute(new Task(i, queue.size())); } pool.shutdown(); } }
执行中, Task: 1, Thread: pool-1-thread-2, queue.size: 0 执行中, Task: 10, Thread: pool-1-thread-3, queue.size: 8 执行中, Task: 11, Thread: pool-1-thread-4, queue.size: 8 执行中, Task: 12, Thread: pool-1-thread-5, queue.size: 8 执行中, Task: 0, Thread: pool-1-thread-1, queue.size: 0 拒绝中, com.example.demo.Task@6d6f6e28, queue.size: 8 拒绝中, com.example.demo.Task@135fbaa4, queue.size: 8 执行中, Task: 2, Thread: pool-1-thread-4, queue.size: 0 执行中, Task: 3, Thread: pool-1-thread-3, queue.size: 1 执行中, Task: 4, Thread: pool-1-thread-1, queue.size: 2 执行中, Task: 5, Thread: pool-1-thread-2, queue.size: 3 执行中, Task: 6, Thread: pool-1-thread-5, queue.size: 4 执行中, Task: 7, Thread: pool-1-thread-4, queue.size: 5 执行中, Task: 9, Thread: pool-1-thread-3, queue.size: 7 执行中, Task: 8, Thread: pool-1-thread-1, queue.size: 6
拒绝中, demo.Task@2d98a335, queue.size: 8 拒绝中, demo.Task@4e50df2e, queue.size: 8 执行中, Task: 11, Thread: pool-1-thread-4, queue.size: 8 执行中, Task: 10, Thread: pool-1-thread-3, queue.size: 8 执行中, Task: 12, Thread: pool-1-thread-5, queue.size: 8 执行中, Task: 0, Thread: pool-1-thread-1, queue.size: 0 执行中, Task: 1, Thread: pool-1-thread-2, queue.size: 0 执行中, Task: 3, Thread: pool-1-thread-4, queue.size: 1 执行中, Task: 2, Thread: pool-1-thread-3, queue.size: 0 执行中, Task: 4, Thread: pool-1-thread-5, queue.size: 2 执行中, Task: 5, Thread: pool-1-thread-2, queue.size: 3 执行中, Task: 6, Thread: pool-1-thread-1, queue.size: 4 执行中, Task: 7, Thread: pool-1-thread-4, queue.size: 5 执行中, Task: 8, Thread: pool-1-thread-3, queue.size: 6 执行中, Task: 9, Thread: pool-1-thread-2, queue.size: 7
可见 JDK17 的 ThreadPoolExecutor ,在通过 execut 提交 runnable 后,不会立即执行被提交的 runnable ,而是等待一段时间。如果在这段等待时间内没有新的 runnable 提交,才开始执行。
![]() | 1 hankli 2023-05-22 16:06:11 +08:00 把 jdk17 的 tpe 复制一份,在 runWorker 方法加个日志,你会发现立即执行了.并没有等待.从执行 runworker 到真正直行你 task 的 run 中间时间有点变长了 2(阶段):pool-1-thread-3Task{no=8, time=168958} 2:pool-1-thread-4Task{no=9, time=194958} 拒绝中, Task{no=11, time=-19455630845391}, queue.size: 8 2:pool-1-thread-5Task{no=10, time=194047} 3(阶段):pool-1-thread-3Task{no=8, time=394249} 2:pool-1-thread-2Task{no=1, time=614927} 3:pool-1-thread-5Task{no=10, time=350700} 拒绝中, Task{no=12, time=-19455631020344}, queue.size: 8 3:pool-1-thread-4Task{no=9, time=333429} 执行中, Task: 10, Thread: pool-1-thread-5, queue.size: 8 执行中, Task: 8, Thread: pool-1-thread-3, queue.size: 8 |
![]() | 2 yodhcn OP @hankli #1 谢谢老哥的指导。 我之后又做了个实验,写了个死循环一直调用 pool.execute(new Task(i, queue.size())) [假设] 不会立即执行被提交的 runnable ,而是等待一段时间。如果在这段等待时间内没有新的 runnable 提交,才开始执行。 [实验] 写死循环一直调用 pool.execute(new Task(i, queue.size())),不断提交新的 runnable ,如果假设成立,被提交的 runnable 将永远不会被执行。 为了方便观察,注释掉 RejectedExecutionHandler 里的打印语句,结果在控制台发现 “执行中, Task...” 日志,与假设矛盾。 正如老哥所说的那样,只是 “从执行 runworker 到真正直行你 task 的 run 中间时间有点变长了” |
![]() | 3 cheneydog 2023-05-22 19:48:06 +08:00 ![]() 所以结论是啥?为啥时间还变长了?有啥优势? |
4 blessingsi 2023-05-22 20:52:01 +08:00 java8: ``` 执行中, Task: 0, Thread: pool-1-thread-1, queue.size: 0, time: 425747251451497 执行中, Task: 1, Thread: pool-1-thread-2, queue.size: 0, time: 425747251525194 执行中, Task: 10, Thread: pool-1-thread-3, queue.size: 8, time: 425747251772510 执行中, Task: 11, Thread: pool-1-thread-4, queue.size: 8, time: 425747251892745 执行中, Task: 12, Thread: pool-1-thread-5, queue.size: 8, time: 425747251928019 拒绝中, Task@4554617c, queue.size: 8, time: 425747251889215 拒绝中, Task@74a14482, queue.size: 8, time: 425747252008173 执行中, Task: 2, Thread: pool-1-thread-3, queue.size: 0, time: 425749253444220 执行中, Task: 3, Thread: pool-1-thread-1, queue.size: 1, time: 425749254108044 执行中, Task: 4, Thread: pool-1-thread-4, queue.size: 2, time: 425749254203373 执行中, Task: 5, Thread: pool-1-thread-5, queue.size: 3, time: 425749254286334 执行中, Task: 6, Thread: pool-1-thread-2, queue.size: 4, time: 425749254359863 执行中, Task: 7, Thread: pool-1-thread-3, queue.size: 5, time: 425751254069256 执行中, Task: 8, Thread: pool-1-thread-2, queue.size: 6, time: 425751259174650 执行中, Task: 9, Thread: pool-1-thread-4, queue.size: 7, time: 425751259199900 ``` java17: ``` 拒绝中, Task@30f39991, queue.size: 8, time: 425953431226281 拒绝中, Task@38af3868, queue.size: 8, time: 425953447958506 执行中, Task: 10, Thread: pool-1-thread-3, queue.size: 8, time: 425953430891601 执行中, Task: 11, Thread: pool-1-thread-4, queue.size: 8, time: 425953431206209 执行中, Task: 1, Thread: pool-1-thread-2, queue.size: 0, time: 425953430740641 执行中, Task: 0, Thread: pool-1-thread-1, queue.size: 0, time: 425953430633193 执行中, Task: 12, Thread: pool-1-thread-5, queue.size: 8, time: 425953431287397 执行中, Task: 3, Thread: pool-1-thread-2, queue.size: 1, time: 425955450935401 执行中, Task: 4, Thread: pool-1-thread-5, queue.size: 2, time: 425955450944853 执行中, Task: 2, Thread: pool-1-thread-4, queue.size: 0, time: 425955450921501 执行中, Task: 6, Thread: pool-1-thread-3, queue.size: 4, time: 425955451482689 执行中, Task: 5, Thread: pool-1-thread-1, queue.size: 3, time: 425955451440625 执行中, Task: 7, Thread: pool-1-thread-2, queue.size: 5, time: 425957453093453 执行中, Task: 8, Thread: pool-1-thread-5, queue.size: 6, time: 425957453281909 执行中, Task: 9, Thread: pool-1-thread-4, queue.size: 7, time: 425957453416090 ``` 实际运行的时间和 sout 看到的顺序是不一样的 |
![]() | 5 yodhcn OP @blessingsi #4 “执行中, Task: 10, Thread: pool-1-thread-3, queue.size: 8, time: 425747251772510” 日志里的 time 时间戳,指的是在 ThreadPoolExecutor#runWorker 运行开始?还是在 ThreadPoolExecutor#runWorker 方法体里调用 task.run(); 之前? |
![]() | 6 kawowa 2023-05-23 07:31:45 +08:00 via iPhone 很有趣的发现,mark 一个 |
![]() | 7 zhiyu1998 2023-05-23 08:53:04 +08:00 cool~ |
8 blessingsi 2023-05-23 09:28:48 +08:00 via Android ![]() @a href="/member/yodhcn">yodhcn 在 run 方法开始的时候记录一下时间。 ``` var now= system.nanotime(); sour("执行中,task" + "xxxx" + now); ``` |
![]() | 9 liudaolunhuibl 2023-05-23 10:23:49 +08:00 ![]() jdk17 比起 jdk8 在 runworker 中真正执行你 task 的 run 方法之前新增了一个方法:clearInterruptsForTaskRun ,注释是这样的:* Ensures that unless the pool is stopping, the current thread * does not have its interrupt set. This requires a double-check * of state in case the interrupt was cleared concurrently with a * shutdownNow -- if so, the interrupt is re-enabled. |
10 blessingsi 2023-05-23 11:13:34 +08:00 看到的打印的顺序和实际方法开始执行的顺序是没有一致性保证的。而且 jdk17 和 jdk8 的 sout 方法实现也变了。 |