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

How to end a thread in executor service if thread takes too long?

示例执行程序服务

 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,我想 end/kill 线程。 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");
            } 

您必须先执行 awaitTermination(),然后检查 return 值,然后再执行 shutdownNow()shutdown() 不保证服务立即停止,它只是停止接收新作业,并等待 所有 个作业按顺序完成。 shutdownNow() 另一方面,停止接受新工作,主动尝试停止所有 运行 任务,并且不启动任何新任务,return 列出所有等待执行的任务职位。

来自 JavaDocs :

The following method shuts down an ExecutorService in two phases, first by calling shutdown to reject incoming tasks, and then calling shutdownNow, if necessary, to cancel any lingering tasks:

 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();
   }
 }

您可以随时调用 future.get(超时...) 如果它还没有完成,它将 return 超时异常...然后你可以调用 future.cancel().

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

如果它没有帮助,那么您调用 shutdownNow() 尝试通过将每个线程的中断标志设置为 true 来取消任务。在这种情况下,如果线程是 blocked/waiting,那么将抛出 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();
    }
}

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

How can I terminate the thread task if it does not connect to server within 2 seconds.

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

然而,在您的情况下,您使用的是 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

In case of a timeout (either connectTimeout or kexTimeout) a SocketTimeoutException is thrown.