我想知道为什么执行器服务实际上可以多次执行相同的线程。因为线程的通常生命周期在终止的 afaik 上结束。
所以
public class TestThread extends Thread {
AtomicInteger counter = new AtomicInteger(0);
@Override
public void run() {
System.out.printf("%dn", counter.addAndGet(1));
}
public static void main(String[] args) throws InterruptedException {
ExecutorService es = Executors.newCachedThreadPool();
TestThread t = new TestThread();
es.execute(t);
es.execute(t);
es.shutdown();
}
}
这适用于我实际上期望非法状态例外的地方,例如在这种情况下:
t.start();
t.start(); =>BAM!
非常感谢帮助解开执行背后的魔力!
ExecutorService.execute(Runnable)
用新的Thread
实例包装它们。如果还打印线程 ID,
@Override
public void run() {
System.out.printf("%d %d%n", counter.addAndGet(1),
Thread.currentThread().getId());
}
您将看到两个不同的线程正在运行。例如
1 10
2 11
ExecutorService 永远不会重新启动线程。 线程永远无法重新启动。
ExecutorService 是一个线程池。 它管理一组长时间运行的线程,每个线程都能够执行许多任务。
当你的代码调用一些 ExeuctorService(es 和一些 Runnable(的 es.submit(r)
时;submit 函数会将你的 runnable 添加到阻塞队列中。
由 ExecutorService 管理的每个线程都有一个 run(( 方法,如下所示:
public void run() {
while (true) {
Runnable task = queue.take();
task.run();
}
}
当然,由于异常和 shutdown(( 机制,它比这更复杂,但这是基本思想。 池线程基本上永远运行,等待任务执行。
start()
方法不会调用两次,实际上甚至不会调用一次:只使用对象的Runnable
接口。实际的Thread
是用每个execute()
创建的,每个都委托给你的run()
方法。
您无法重新启动线程,但可以检测多次使用的线程;
测试代码:
package com.stackoverflow.test;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
public class TestOfCachedThreadPool {
private static final int AMOUNT = 1000000;
private static final class TestThread implements Runnable {
private Map<Long, Long> mapOfUsage;
private TestThread(Map<Long, Long> mapOfUsage) {
this.mapOfUsage = mapOfUsage;
}
@Override
public void run() {
synchronized (mapOfUsage) {
Long numberOfThreads=mapOfUsage.get(Thread.currentThread().getId());
if(numberOfThreads==null){
mapOfUsage.put(Thread.currentThread().getId(), 1l);
}else{
mapOfUsage.put(Thread.currentThread().getId(), ++numberOfThreads);
}
}
}
}
public static void main(String[] args) {
ThreadFactory threadFactory = Executors.defaultThreadFactory();
final Map<Long, Long> mapOfUsage = new HashMap<>(AMOUNT * 2);
ExecutorService service = Executors.newCachedThreadPool();
for(int i=0;i<AMOUNT;i++){
service.execute(threadFactory.newThread(new TestThread(mapOfUsage)));
}
for(Map.Entry<Long, Long> entry: mapOfUsage.entrySet()){
if(entry.getValue()>1){
System.out.println("Thread with id "+entry.getKey() +" was used "+entry.getValue()+ " times");
}
}
}
}
输出:
ID 为 9 的线程被使用了 27198 次
ID 为 11 的线程被使用了 1810 次
ID 为 13 的线程被使用了 1294 次
ID 为 15 的线程被使用了 3347 次
ID 为 17 的线程被使用了 6709 次
ID 为 19 的线程被使用了 7259 次
ID 为 21 的线程被使用了 39335 次
ID 为 23 的线程被使用了 13552 次
ID 为 25 的线程被使用了 535 次
ID 为 27 的螺纹被使用了 19533 次
ID 为 29 的线程被使用了 113495 次
ID 为 31 的线程被使用了 62713 次
ID 为 35 的线程已使用 94103 次
ID 为 33 的线程已使用 53641 次
ID 为 5328 的螺纹被使用了 18922 次
ID 为 16388 的线程已使用 28501 次
ID 为 16384 的线程被使用了114677次
ID 为 16386 的线程被使用了 39 次
ID 为 16698 的线程已使用 60450 次
ID 123096的线程被使用了 19944 次
ID 123102 的线程已使用 60961 次
ID 为 123115 的线程被使用了 24246 次
ID 275492 的线程被使用了 108399 次
ID 为 275490 的线程已使用 11973 次
ID 380143 的线程被使用了 10433 次
ID 为 363358 的线程已使用 55989 次
ID 692626的线程被使用了 6016 次
ID 为 909079 的线程已使用 25782 次
ID 为 965801 的线程被使用了 32 次
ID 948919的线程被使用了 1782 次
ID 为 948872 的线程使用了 4 次
ID 为 938802 的线程被使用 24 次
ID 923558的线程被使用了 7302 次