Java 程序挂起时线程不';不要终止

Java 程序挂起时线程不';不要终止,java,multithreading,Java,Multithreading,我有这种奇怪的行为。我的程序挂起,即使我正在设置强制终止它的时间。有人能指出这种奇怪的行为是什么吗 这是我的代码,我从这里开始线程 protected void pendingTaskStarter() throws Exception { ExecutorService service = Executors.newFixedThreadPool(maxThreadNum); ArrayList<Future<Runnable>> futures = n

我有这种奇怪的行为。我的程序挂起,即使我正在设置强制终止它的时间。有人能指出这种奇怪的行为是什么吗

这是我的代码,我从这里开始线程

protected void pendingTaskStarter() throws Exception {
    ExecutorService service = Executors.newFixedThreadPool(maxThreadNum);
    ArrayList<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();

    System.out.println("max thread num: " + maxThreadNum);
    for(int i=0;i<maxThreadNum;i++){

        Thread t = new PendingTaskConsumer();
        Future<?> f=service.submit(t);
        futures.add((Future<Runnable>) f);  
    }

    for (Future<?> future:futures) {
        future.get(5l,TimeUnit.MINUTES); // maximum thread's life is 5min (5l <-- 5 in long )
    }   
    service.shutdownNow();

}

该程序运行在
Linux(Ubuntu)
上,并使用
openjdk-7-jdk后台(1.7版)
很好。。。似乎缺少正确的异常处理

/**  
 * Waits if necessary for at most the given time for the computation  
 * to complete, and then retrieves its result, if available.  
 *  
 * @param timeout the maximum time to wait  
 * @param unit the time unit of the timeout argument  
 * @return the computed result  
 * @throws CancellationException if the computation was cancelled  
 * @throws ExecutionException if the computation threw an
 * exception  
 * @throws InterruptedException if the current thread was interrupted
 * while waiting  
 * @throws **TimeoutException if the wait timed out**  
 */  
V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException;
如果您呼叫
future.get(5l,TimeUnit.MINUTES)过期,然后抛出一个
异常
,并且您的
服务
永远不会关闭

因此(可以假设)它的内部线程仍在运行,至少是执行长时间运行的任务的线程)。看到这些是非守护进程线程(您必须自定义执行器的
ThreadFactory
),这些挂起的线程会阻止JVM关闭

如果您希望强制终止任务,您可以:

  • 将可运行任务设计为响应
    线程.isInterrupted()
    ,并在看到这一点时退出。(现在关闭
    的实际效果是设置
    执行器的线程的中断标志)
  • 如果您不能(因为您的线程被某个库中不侦听中断的方法阻塞),那么拥有dameon线程似乎是唯一的选择

  • 但无论如何,我会将
    执行器的关闭放在更早的地方,或者放在
    finally
    子句中。

    正如@GPI在其回答中已经指出的那样,如果您的任务没有通过
    thread.interrupt()响应线程中断,取消将无法正常工作。看到或看到

    但是,即使您的任务在线程被中断时没有立即停止(=设置了中断标志),您也可以使方法超时。只是不要通过调用未来的
    方法的每一个
    get()
    方法来听任务完成!这是没有必要的,因为你对他们的结果并不感兴趣。只需关闭您的
    ExecutorService
    ,等待其终止

    protected void pendingTaskStarter() throws InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(maxThreadNum);
    
        for (int i = 0; i < maxThreadNum; i++) {
            service.submit(new PendingTaskConsumer());
        }
    
        // Shutdown service.
        // This will continue to process already submitted tasks.
        service.shutdown();
    
        try {
            // wait at least 5 minutes for the tasks to complete
            if (!service.awaitTermination(5, TimeUnit.MINUTES)) {
                // still not done yet -> force shutdown
                // this will interrupt currently running tasks.
                service.shutdownNow();
            }
        } catch (InterruptedException ex) {
            // someone interrupted this thread. Shutdown tasks immediately
            service.shutdownNow();
            // propagate exception
            throw ex;
        }
    }
    
    protectedvoid pendingTaskStarter()引发中断异常{
    ExecutorService=Executors.newFixedThreadPool(maxThreadNum);
    对于(int i=0;i强制关机
    //这将中断当前正在运行的任务。
    service.shutdownNow();
    }
    }捕获(中断异常例外){
    //有人中断了此线程。请立即关闭任务
    service.shutdownNow();
    //传播异常
    掷骰子;
    }
    }
    
    那么这里发生了什么

    • 首先,提交所有任务
    • 然后对执行器服务调用
      shutdown()
      。请注意,该服务将被删除
    • 现在,我们通过调用超时5分钟来等待服务终止。如果此方法返回
      true
      ,这意味着服务已在时间内终止,则一切正常,我们已完成。但如果在5分钟后返回
      false
      ,则表示服务仍在运行,因为有些任务需要更多时间才能完成
    • 在这种情况下,我们通过调用
      shutdownNow()
      立即关闭服务。请注意,此方法不会阻塞!它只是试图取消所有正在运行的任务,通常是中断当前正在执行这些任务的线程。这就是为什么您的任务应该正确响应线程中断!如果他们不这样做,中断线程将毫无效果
    • 无论
      shutdownow
      是否成功,我们都已完成,不再等待。因此,可能仍有一些任务正在运行,因为它们在线程中断时不会做出反应(通常是因为任务未正确执行或是故意不间断地执行)。但我们根本不在乎
    • 请注意异常处理程序:当另一个线程在方法
      waittermination
      中等待时中断调用我们方法的线程时,将抛出
      InterruptedException
      。我们通过关闭服务并重新抛出异常来处理它!这是一件好事,使我们的方法成为一个可以自行取消的长时间运行的操作
    该程序预计运行多长时间?您等待它完成的时间有多长?我在这一层上有一个API,如果这个程序没有在20分钟内终止,那么它会重新启动这个程序正在运行的机器(1)为什么
    PendingTaskConsumer
    是从
    线程
    派生出来的?它不是一个线程,而是由
    ExecutorService
    维护的另一个线程执行的任务。(2)
    PendingTaskConsumer()
    是方法调用吗?如果否,则可能缺少
    new
    关键字。@isnot2bad PendingTaskConsumer is class,在问题中,我没有在前面添加关键字“new”@nafas OK。但是你仍然不应该从这里的
    线程中派生
    PendingConsumer
    只是一个
    Runnable
    Callable
    ,而不是一个线程本身!(线程由执行器内部管理!)非常有趣的伙伴,我从未考虑过这一点。但我会试试,让你知道。这是一个非常清楚的解释。我喜欢你提到的那一部分,没有必要跟踪未来。我会试试,让你知道我会非常惊讶的,它成功了。我相信我的前任;成功了。即使线程没有被终止。我摆脱了那种方法。然后,一旦其他一切都完成了,我所需要做的就是添加Sy
    protected void pendingTaskStarter() throws InterruptedException {
        ExecutorService service = Executors.newFixedThreadPool(maxThreadNum);
    
        for (int i = 0; i < maxThreadNum; i++) {
            service.submit(new PendingTaskConsumer());
        }
    
        // Shutdown service.
        // This will continue to process already submitted tasks.
        service.shutdown();
    
        try {
            // wait at least 5 minutes for the tasks to complete
            if (!service.awaitTermination(5, TimeUnit.MINUTES)) {
                // still not done yet -> force shutdown
                // this will interrupt currently running tasks.
                service.shutdownNow();
            }
        } catch (InterruptedException ex) {
            // someone interrupted this thread. Shutdown tasks immediately
            service.shutdownNow();
            // propagate exception
            throw ex;
        }
    }