2013-10-14 45 views
1

我可以多次看到这个问题。再次问这个道歉。我有一个奇怪的问题。终止Java线程

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

由于要提交的线程数量很大,因此线程会一直挂起直到提交所有任务。

有什么办法,这些线程一旦执行完成就可以正常终止?

+0

如果你调用'ExecutorService.shutdown()'的ExecutorService的将停止其所有的线程(通过允许他们从他们的运行方法返回)完成所有工作。 – Dev

+0

谢谢开发。有没有办法在执行完成后立即关闭线程,而不是等待所有其他线程完成? – user1401472

+0

直到ExecutorService关闭时,正在运行的线程或线程才会完成。线程通常会重用于多个作业。如果您想在特定作业完成后关闭'ExecutorService',则可以在该作业的'Future'和'shutdownNow()'执行器返回时阻止。 – Dev

回答

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) { 
      } 
     } 
    } 
} 
+0

KeepAilveTime不适用于我。我的印象是,在说30秒后,我指定为keepAliveTime,eclipse调试环境不应该显示线程正在运行。但是那没有发生。我仍然看到线程生活,虽然它不处理。我知道这个线程应该是无害的,但我不想在我的应用程序中存在太多的悬挂线程。我错过了什么吗? – user1401472

+1

也许你的'corePoolSize'参数太高? –

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线程)没有用处,因为它实际上并没有提高并发性。只要将执行者限制在合理数量的线程中,“挂起”类型的问题就可能会消失。

+0

谢谢蒂姆。这与你提到的完全相同。我不想让已经完成执行的线程继续存在。每个线程已经在单独的收集中收集所需的结果,并且不再需要这些线程。所以即使我使用fixedThread,它仍然会等待其他线程在终止之前完成。 – user1401472