我可以多次看到这个问题。再次问这个道歉。我有一个奇怪的问题。终止Java线程
我有一份工作,通过ExecutorService提交数千个作业作为单独的Runnable任务。这是在一个简单的循环中完成的。 for循环结束后,我调用service.shutdown(),然后调用awaitTermination。
由于要提交的线程数量很大,因此线程会一直挂起直到提交所有任务。
有什么办法,这些线程一旦执行完成就可以正常终止?
我可以多次看到这个问题。再次问这个道歉。我有一个奇怪的问题。终止Java线程
我有一份工作,通过ExecutorService提交数千个作业作为单独的Runnable任务。这是在一个简单的循环中完成的。 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) {
}
}
}
}
KeepAilveTime不适用于我。我的印象是,在说30秒后,我指定为keepAliveTime,eclipse调试环境不应该显示线程正在运行。但是那没有发生。我仍然看到线程生活,虽然它不处理。我知道这个线程应该是无害的,但我不想在我的应用程序中存在太多的悬挂线程。我错过了什么吗? – user1401472
也许你的'corePoolSize'参数太高? –
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
线程)没有用处,因为它实际上并没有提高并发性。只要将执行者限制在合理数量的线程中,“挂起”类型的问题就可能会消失。
谢谢蒂姆。这与你提到的完全相同。我不想让已经完成执行的线程继续存在。每个线程已经在单独的收集中收集所需的结果,并且不再需要这些线程。所以即使我使用fixedThread,它仍然会等待其他线程在终止之前完成。 – user1401472
如果你调用'ExecutorService.shutdown()'的ExecutorService的将停止其所有的线程(通过允许他们从他们的运行方法返回)完成所有工作。 – Dev
谢谢开发。有没有办法在执行完成后立即关闭线程,而不是等待所有其他线程完成? – user1401472
直到ExecutorService关闭时,正在运行的线程或线程才会完成。线程通常会重用于多个作业。如果您想在特定作业完成后关闭'ExecutorService',则可以在该作业的'Future'和'shutdownNow()'执行器返回时阻止。 – Dev