1

我可以看到这个问题被问了很多次。很抱歉再次问这个问题。我有一个奇怪的问题。

我有一份工作通过 ExecutorService 作为单独的 Runnable 任务提交数千个工作。这是在一个简单的 for 循环中完成的。for 循环结束,我调用 service.shutdown(),然后是 awaitTermination。

由于要提交的线程数量巨大,线程一直挂起,直到所有任务都提交。

有什么办法可以在执行完成后立即优雅地终止这些线程?

4

2 回答 2

1

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) {
            }
        }
    }
}
于 2013-10-14T21:33:18.707 回答
0

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线程)是没有用的,因为它实际上并没有让你获得更多的并发性。只需将执行程序限制在合理数量的线程上,“挂起”类型的问题可能就会消失。

于 2013-10-14T18:34:47.500 回答