1

Sample executor service

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

Right here is a sample code of my executor service. But with this logic when I meet a server that fails to connect or takes too long to connect it creates a a hang time within my application. I want to end/kill the thread if it takes longer than x amount of time to connect. How can I terminate the thread task if it does not connect to server within 2 seconds.

Attempt

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

I added the following code but apparently it does not end the thread if it takes longer than 2000 milliseconds.

Attempt 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");
            } 
Jesse
  • 1,694
  • 6
  • 23
  • 61

4 Answers4

1

You have to do awaitTermination() first, then check the return value, and then do shutdownNow(). shutdown() does not guarantee instant stoppage of the service, it just stops taking new jobs, and waits for all jobs to complete in order. shutdownNow() on the other hand, stops taking new jobs, actively attempts to stop all running tasks, and does not start any new one, returning a list of all waiting-to-execute jobs.

From 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();
   }
 }
Subhranil
  • 821
  • 1
  • 8
  • 21
1

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

This is difficult thing to do typically because even if you interrupt the thread (like the other answers mention) there's no guarantee that the thread will stop. Interrupt just sets a flag on the thread and it's up to the code to detect the status and stop. This means that a ton of threads may be in the background waiting for the connects.

In your case however you are using the ch.ethz.ssh2.Connection.connect() method. Turns out there is a connect method that takes a timeout. I think you want the following:

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

To quote from the connect method javadocs:

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

Gray
  • 108,756
  • 21
  • 270
  • 333
  • I assume null should be my server/host name? API shows that it's a verifer should I leave it null? – Jesse Jun 19 '17 at 14:34
  • 1
    All I saw @Jesse is that the `connect()` call is the same as `connect(null, 0,0)`. I think it is a verifier. – Gray Jun 19 '17 at 14:42
  • Thank you so much sir. I've been looking through the API and this method slipped my sight. It works as intended. – Jesse Jun 19 '17 at 14:51
0

You can always call future.get(timeout...) It will return timeout exception if it did not finish yet... then you can call future.cancel().

Akash
  • 529
  • 5
  • 12
0

As long as you deal with threads in Java the only safe way to stop the thread is to interrupt it. You can call shutdown() first and then wait. This method doesn't interrupt threads.

If it doesn't help then you call shutdownNow() which tries to cancel tasks by setting interrupted flag of each thread to true. In that case if threads are blocked/waiting then InterruptedException will be thrown. If you check interrupted flag somewhere inside your tasks then you are good too.

But if you have no other choice but to stop threads you still can do it. One possible solution of getting access to workers is to trace all created threads inside ThreadPoolExecutor with help of custom thread factory.

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

This is sure unsafe but should fit your requirements. In this case it's able to stop while(true) loop. Cancelling tasks won't be able to do that.

Andrey Cheboksarov
  • 629
  • 1
  • 5
  • 10