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 1
所以结论是啥?为啥时间还变长了?有啥优势?
|
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 1
|
9
liudaolunhuibl 2023-05-23 10:23:49 +08:00 1
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 方法实现也变了。
|