2017-06-15 34 views
1

检体执行服务如果线程花费太长时间,如何在执行程序服务中结束线程?

static class MyRunnable implements Runnable { 

    private String serverName; 

    public MyRunnable(String serverName) { 
     super(); 
     this.serverName = serverName; 
    } 

    @Override 
    public void run() { 
     ... 
     conn = new ch.ethz.ssh2.Connection(serverName); 
     conn.connect(); 

     boolean isAuthenticated = conn.authenticateWithPassword(user, pass); 
     logger.info("Connecting to " + server); 

     if (isAuthenticated == false) { 
      logger.info(server + " Please check credentials"); 
     } 

     sess = conn.openSession(); 
     ... 

    } 

} 

public static void main(String[] args) { 
    List<String> serverList = ...; 
    ExecutorService executor = Executors.newFixedThreadPool(20); 

    for (String serverName : serverList) { 
     MyRunnable r = new MyRunnable(serverName); 
     executor.execute(r); 
    } 

    executor.shutdown(); 
    executor.awaitTermination(1, TimeUnit.HOURS); 
} 

就在这里是我的遗嘱执行人服务的示例代码。但有了这种逻辑,当我遇到无法连接的服务器或连接时间过长时,它会在我的应用程序中创建一个挂起时间。如果连接时间超过x时间,我想结束/终止线程。如果在2秒内没有连接到服务器,我该如何终止线程任务。

尝试

 ThreadPoolExecutor executor = new ThreadPoolExecutor(
       10, 25, 500, TimeUnit.MILLISECONDS, 
       new LinkedBlockingQueue<>(1)); 

添加以下代码,但显然如果超过2000毫秒时间越长,不结束线程。

尝试2

Future<?> future = executor.submit(new task)); 
      try { 
       future.get(2000, TimeUnit.MILLISECONDS); // This waits timeout seconds; returns null 
      } 

      catch(TimeoutException e) { 
       future.cancel(true); 
       // System.out.println(server + "name"); 
      } 
+0

关闭另一个线程的连接以导致Runnable中的异常。 – JimmyB

+0

还有另一种使用超时的连接方法。 – assylias

回答

1

如何在2秒内未连接到服务器的情况下终止线程任务。

这很难做到,因为即使你中断了线程(就像其他答案中提到的那样),也不能保证线程会停止。中断只是在线程上设置一个标志,并由代码来检测状态并停止。这意味着大量的线程可能在后台等待连接。

然而,在您的情况下,您正在使用ch.ethz.ssh2.Connection.connect()方法。结果发现有一个connect method that takes a timeout。我想你想以下几点:

// try to connect for 2 seconds 
conn.connect(null, 2000, 0); 

要从connect method javadocs引用:

在超时的情况下(无论是connectTimeout或kexTimeout)一个SocketTimeoutException被抛出。

+0

我认为空应该是我的服务器/主机名? API显示,如果我将它保留为空,它就是一个优点。 – Jesse

+1

我看到的所有@Jesse都是'connect()'调用和'connect(null,0,0)'相同。我认为这是一个验证者。 – Gray

+0

谢谢你,先生。我一直在寻找API,这种方法滑过我的视线。它按预期工作。 – Jesse

0

你要做awaitTermination(),然后再检查返回值,然后做shutdownNow()shutdown()并不保证服务即时停止,它只是停止采取新的工作,并等待所有工作按顺序完成。另一方面,shutdownNow()停止接受新的工作,主动尝试停止所有正在运行的任务,并且不会启动任何新的工作,返回所有等待执行的工作列表。

JavaDocs

以下方法关闭在两个相的ExecutorService, 首先通过调用shutdown拒绝传入任务,然后调用 shutdownNow时,如果必要的话,取消任何挥之不去的任务:

void shutdownAndAwaitTermination(ExecutorService pool) { 
    pool.shutdown(); // Disable new tasks from being submitted 
    try { 
    // Wait a while for existing tasks to terminate 
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) { 
     pool.shutdownNow(); // Cancel currently executing tasks 
     // Wait a while for tasks to respond to being cancelled 
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) 
      System.err.println("Pool did not terminate"); 
    } 
    } catch (InterruptedException ie) { 
    // (Re-)Cancel if current thread also interrupted 
    pool.shutdownNow(); 
    // Preserve interrupt status 
    Thread.currentThread().interrupt(); 
    } 
} 
+0

为什么-1任何人?答案似乎合法 –

0

您可以随时调用的Future.get(超时...) 它将返回超时异常,如果它没有科幻你还可以调用future.cancel()。

0

只要你在Java中处理线程,停止线程的唯一安全方法就是中断它。您可以先致电shutdown(),然后等待。此方法不会中断线程。

如果它没有帮助,那么您可以拨打shutdownNow(),通过将每个线程的中断标志设置为true来尝试取消任务。在这种情况下,如果线程被阻塞/等待,则会抛出InterruptedException。如果你在任务内部的任何地方检查中断标志,那么你也很好。

但是,如果你没有别的选择,只能停止线程,你仍然可以做到这一点。获得访问工作者的一个可能的解决方案是在自定义线程工厂的帮助下跟踪ThreadPoolExecutor内的所有创建的线程。

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.*; 

public class TestThreadPoolEx { 

    static class CustomThreadFactory implements ThreadFactory { 
     private List<Thread> threads = new ArrayList<>(); 

     @Override 
     public Thread newThread(Runnable r) { 
      Thread t = new Thread(r); 
      threads.add(t); 
      return t; 
     } 

     public List<Thread> getThreads() { 
      return threads; 
     } 

     public void stopThreads() { 
      for(Thread t : threads) { 
       if(t.isAlive()) { 
        try { 
         t.stop(); 
        } catch (Exception e) { 
         //NOP 
        } 
       } 
      } 
     } 
    } 

    public static void main(String[] args) throws InterruptedException { 
     CustomThreadFactory factory = new CustomThreadFactory(); 
     ExecutorService ex = Executors.newFixedThreadPool(1, factory); 
     ex.submit(() -> { 
      while(true); 
     }); 
     ex.shutdown(); 
     ex.awaitTermination(5, TimeUnit.SECONDS); 
     ex.shutdownNow(); 
     ex.awaitTermination(5, TimeUnit.SECONDS); 
     factory.stopThreads(); 
    } 
} 

这肯定是不安全的,但应该符合您的要求。在这种情况下,它可以在(真)循环时停止。取消任务将无法做到这一点。

相关问题