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

时间:2017-06-15 17:59:22

标签: java multithreading ganymede ssh2-exec

示例执行者服务

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

4 个答案:

答案 0 :(得分: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。

答案 1 :(得分: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();
   }
 }

答案 2 :(得分:0)

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

答案 3 :(得分: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();
    }
}

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