Siva Arunachalam
Siva Arunachalam

Reputation: 7750

Java - Get thread state

I am using ThreadPoolExecutor to run the threads.

ExecutorService executorService = Executors.newCachedThreadPool();
Future<?> future = executorService.submit(new MyRunnable());

Based on some conditions, I need to terminate the long running thread and start the same thread instance again(for some cleanup operations).

Since I have a future object of the thread, I can easily check if it is still running.

 future.isDone()

If it is running, I can send a interrupt signal by using

 future.cancel(true);

In the MyRunnable class, the interrupt signal is handled. But this condition is checked at the beginning of the loop.

The problem is future.isDone() returns true as soon as interrupt signal is sent. But I need to wait till the thread instance is really completed.

Is there any way to check if the thread is really running/completed?

Upvotes: 0

Views: 470

Answers (2)

vanOekel
vanOekel

Reputation: 6548

The Apidoc also mentions that future.isDone() returns true if future.cancel() was called, i.e. it does not always tell you if the task has finished. To check if the task is finished, you need acces to the Runnable and then you can check if the task has completed or wait for it to complete.
Compare the code below with the output shown beneath it, I think that will give you an idea of your options:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class Q21227864 {

public static void main(String[] args) {

    ExecutorService executorService = Executors.newCachedThreadPool();
    Future<?> future = executorService.submit(new MyRunnable());
    sleep(100L);
    future.cancel(true);
    System.out.println("Future done: " + future.isDone());
    sleep(100L);
    future.cancel(true);
    System.out.println("Future done: " + future.isDone());
    sleep(500L);
    System.out.println("Future done: " + future.isDone());

    System.out.println("---");

    MyRunnable mr = new MyRunnable();
    future = executorService.submit(mr);
    sleep(100L);
    future.cancel(true);
    System.out.println("Runnable done: " + mr.isDone());
    sleep(100L);
    System.out.println("Runnable done: " + mr.isDone());
    mr.waitForCleanup();
    System.out.println("Runnable done: " + mr.isDone());

    executorService.shutdownNow();
}

public static void sleep(long timeMs) { 
    try { Thread.sleep(timeMs); } catch (Exception ignored) {}
}

static class MyRunnable implements Runnable {

    final CountDownLatch completed = new CountDownLatch(1);

    public void run() {

        try {
            System.out.println("Sleeping loop");
            Thread.sleep(1000L);
            System.out.println("Sleeping loop done");
        } catch (Exception e) {
            System.out.println("Stopped loop: " + e);
        }
        try {
            System.out.println("Sleeping cleanup");
            Thread.sleep(300L);
            System.out.println("Sleeping cleanup done");
        } catch (Exception e) {
            System.out.println("Stopped cleanup: " + e);
        }
        completed.countDown();
    }

    public boolean isDone() {
        return (completed.getCount() == 0);
    }

    public void waitForCleanup() {
        try { completed.await(); } catch (Exception ignored) {}
    }

}

}

Output:

Sleeping loop
Future done: true
Stopped loop: java.lang.InterruptedException: sleep interrupted
Sleeping cleanup
Future done: true
Sleeping cleanup done
Future done: true
---
Sleeping loop
Runnable done: false
Stopped loop: java.lang.InterruptedException: sleep interrupted
Sleeping cleanup
Runnable done: false
Sleeping cleanup done
Runnable done: true

Upvotes: 1

Evgeniy Dorofeev
Evgeniy Dorofeev

Reputation: 136122

I don't think future.isDone() returns true as soon as interrupt signal is sent. All ThreadPoolExecutor tasks are executed via FutureTask.run() method

public class FutureTask<V> implements RunnableFuture<V> {
    ...    
    public boolean isDone() {
        return state != NEW;
    }

    public void run() {
    ...
            try {
                Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran;
                    try {
                        result = c.call();   <-- this invokes your code
                        ran = true;
                    } catch (Throwable ex) {
                        result = null;       <-- if you threw InterruptedException
                        ran = false;
                        setException(ex);    <-- state changes here
                    }
                    if (ran)
                        set(result);         <-- if your code simply returns then state changes here
                }
    ...

Upvotes: 0

Related Questions