Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't stop a task which is started using ExecutorService

Sorry I have to open a new thread to describe this problem.

This morning I asked this question, there're some replies but my problem is still not solved.

This time I will attach some runnable code(simplified but with the same problem) for you to reproduce the problem:

public class ThreadPoolTest {
    public static void main(String[] args) throws Exception {
        final ExecutorService taskExecutor = Executors.newFixedThreadPool(5);
        Future<Void> futures[] = new Future[5];
        for (int i = 0; i < futures.length; ++i)
            futures[i] = startTask(taskExecutor);

        for (int i = 0; i < futures.length; ++i)
            System.out.println("futures[i].cancel(true): " + futures[i].cancel(true));

        System.out.println("Cancel DONE.");
        taskExecutor.shutdown();
    }

    private static Future<Void> startTask(final ExecutorService taskExecutor) {
        Future<Void> f = taskExecutor.submit(new Callable<Void>() {
            public Void call() throws Exception {
                try {
                    downloadFile(new URI("http://stackoverflow.com"));
                    while(true) {
                        System.out.println(Thread.currentThread().getName() + ": " + Thread.currentThread().isInterrupted());
                        if(Thread.currentThread().isInterrupted())
                            break;
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return null;
            } 
        });
        return f;
    }

    private static void downloadFile (final URI uri) throws Exception {
//        if(true) return;
        Socket socket = new Socket (uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort());
        return;
    }
}

The code above will most likely be trapped in an infinite loop(you may want to run the code multiple times to witness what I saw), as you can see in the main method I have called futures[i].cancel(true) for all tasks, I don't know why this is happening, this has been torturing me for more than a day.

Your help will be greatly appreciated.

like image 820
neevek Avatar asked Jan 23 '26 23:01

neevek


1 Answers

I've played with your code, and noticed that the thread's interrupt status is sometimes true before the socket creation, and false after.

I have tried interrupting a thread and calling the Socket constructor, and the thread always stays interrupted after. I also tried removing the shutdown of the threadpool, and the problem continued to happen.

Then I have tried using 5 different URIs, rather than always the same one. And the problem never happened.

So I wrote this simple program, showing that the thread pool is not the culprit, but the socket is:

public static void main(String[] args) throws Exception {
    final URI uri = new URI("http://stackoverflow.com");
    for (int i = 0; i < 5; i++) {
        Runnable r = new Runnable() {
            @Override
            public void run() {
                Thread.currentThread().interrupt();
                System.out.println(Thread.currentThread().isInterrupted());
                try {
                    Socket socket = new Socket (uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort());
                }
                catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().isInterrupted());
            }
        };
        new Thread(r).start();
    }
}

And indeed, when 5 threads create a socket to the same host and port, 4 of them have their interrupt status cleared.

Then I tried to synchronize the socket creation (on a single lock, but I guess you might use one lock per host/port) :

synchronized(lock) {
    try {
        Socket socket = new Socket (uri.getHost(), uri.getPort() == -1 ? 80 : uri.getPort());
    }
    catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

and TADA... the problem disappeared. I would open a bug at Oracle to signal the problem.

like image 109
JB Nizet Avatar answered Jan 25 '26 14:01

JB Nizet



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!