我可以看到这个问题被问了很多次。很抱歉再次问这个问题。我有一个奇怪的问题。
我有一份工作通过 ExecutorService 作为单独的 Runnable 任务提交数千个工作。这是在一个简单的 for 循环中完成的。for 循环结束,我调用 service.shutdown(),然后是 awaitTermination。
由于要提交的线程数量巨大,线程一直挂起,直到所有任务都提交。
有什么办法可以在执行完成后立即优雅地终止这些线程?
我可以看到这个问题被问了很多次。很抱歉再次问这个问题。我有一个奇怪的问题。
我有一份工作通过 ExecutorService 作为单独的 Runnable 任务提交数千个工作。这是在一个简单的 for 循环中完成的。for 循环结束,我调用 service.shutdown(),然后是 awaitTermination。
由于要提交的线程数量巨大,线程一直挂起,直到所有任务都提交。
有什么办法可以在执行完成后立即优雅地终止这些线程?
ThreadPoolExecutor
您可以在不调用的情况下创建一个新的java.util.concurrent.Executors
:
int corePoolSize = 0;
int maximumPoolSize = 64;
int keepAliveTime = 5000;
ExecutorService executorService =
new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,
TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());
来自 javadoc:“如果池当前有多个 corePoolSize 线程,如果多余的线程空闲时间超过 keepAliveTime,则将终止它们”
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
编辑:
这是一个小例子,如果你在 Eclipse 调试环境中运行它,你应该会看到线程来来去去:
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ExecutorTest {
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(0, 64, 1000,
TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());
for (int i = 0; i <= 500; i ++) {
try {
Thread.sleep(new Random().nextInt(200));
} catch (InterruptedException e) {
}
executorService.submit(new TestTask());
}
}
public static class TestTask implements Runnable {
public void run() {
try {
Thread.sleep(new Random().nextInt(1500));
} catch (InterruptedException e) {
}
}
}
}
shutdownNow()
让您中止未决任务的执行是正确的。如果你的目标是做足够的工作来计算一些结果(这将需要不确定数量的任务),但是一旦你得到结果就停止做更多的工作,那么你将需要一些方法让Runnable
对象向循环它应该停止循环。就像是:
ExecutorService svc = ...
AtomicBoolean done = new AtomicBoolean();
for (int i=0; i < jobs.length; i++) {
svc.submit(new MyRunnable(done, jobs[i]));
if (done.get()) break;
}
class MyRunnable implements Runnable {
private final Whatever job;
private final AtomicBoolean done;
MyRunnable (AtomicBoolean done, Whatever job) { this.done = done; this.job = job; }
public void run() {
if (done).get() return;
//do the work
if (somehowComputeThatTheWorkIsComplete) done.set(true);
}
}
如果由于启动了太多线程而导致事情挂起,那么请考虑使用Executors.newFixedThreadPool() - 计算机实际上不能同时执行比可用逻辑核心数更多的工作。所以使用无界线程池(最多可以创建Integer.MAX_VALUE
线程)是没有用的,因为它实际上并没有让你获得更多的并发性。只需将执行程序限制在合理数量的线程上,“挂起”类型的问题可能就会消失。