0

I have the following code:

private static final AtomicBoolean shutdown = new AtomicBoolean(false);

public static void main(final String... args) {

    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        shutdown.set(true);
        executorService.shutdown();
        try {
            executorService.awaitTermination(SHUTDOWN_TIMEOUT.getSeconds(), TimeUnit.SECONDS);
        } catch (InterruptedException e) {
               executorService.shutdownNow();
        }
    }));

    executorService = Executors.newFixedThreadPool(2);
    for (int i = 0; i < 2; i++) {
        executorService.execute(create());
    }
}

private static Runnable create() {
    return new Runnable() {
        @Override
        public void run() {
            while (!shutdown.get()) {
                try {
                    Thread.sleep(5000);
                    System.out.println("Hatella" + Thread.currentThread().getName());
                } catch (Throwable t) {
                }
            }
        }
    };
}

This code is working perfectly fine but I wanted to write this code in much simpler way so that I don't have to check the shutdown flag status in each while loop. Any idea what can I do to fix this and achieve the same thing.

hatellla
  • 4,796
  • 8
  • 49
  • 101

2 Answers2

1

shutdown() will only make the ExecutorService not accepting more tasks, but it will continue executing all pending tasks to the end. Since you actually want to stop executing tasks, you should use shutdownNow() in the first place, which will send an interruption signal.

public static void main(final String... args) {
    ExecutorService executorService = Executors.newFixedThreadPool(2);

    Runtime.getRuntime().addShutdownHook(new Thread(() -> {
        executorService.shutdownNow();
        try {
            executorService.awaitTermination(
                SHUTDOWN_TIMEOUT.getSeconds(),TimeUnit.SECONDS);
        } catch (InterruptedException e) {}
    }));

    for (int i = 0; i < 2; i++) {
        executorService.execute(create());
    }
}

private static Runnable create() {
    return () -> {
        while(!Thread.interrupted()) {
            try {
                Thread.sleep(5000);
                System.out.println("Hatella" + Thread.currentThread().getName());
            }
            catch(InterruptedException ex) {
                break;
            }
            catch (Throwable t) {
            }
        }
        System.out.println("thread exit " + Thread.currentThread().getName());
    };
}

The interruption flag can not only be queried via Thread.interrupted(), it will also make blocking actions like Thread.sleep(…) terminate earlier, reporting the situation via InterruptedException. In both cases, when Thread.interrupted() returned true or when the InterruptedException has been thrown, the interrupt status will be reset, so it’s crucial to either, react on it immediately or remember that you received it. So in the above example, catch(InterruptedException ex) contains a break, to end the loop.

But as shown, interruption does not terminate a thread but allows to react on it, e.g. by cleaning up when necessary, before exiting.

Note that when the only lengthy operations are the blocking ones, you don’t need to poll the interrupted status manually at all, e.g. the following would work too:

private static Runnable create() {
    return () -> {
        while(true) {
            try {
                Thread.sleep(5000);
                System.out.println("Hatella" + Thread.currentThread().getName());
            }
            catch(InterruptedException ex) {
                System.out.println("got "+ex+", "+Thread.interrupted());
                break;
            }
            catch (Throwable t) {
            }
        }
        System.out.println("thread exit");
    };
}

Since this code does not check-and-reset the interrupted state via Thread.interrupted(), the signal will persist until the next invocation of Thread.sleep, which will be soon enough to appear as an immediate response, as the code executed between two sleep calls is short.

Holger
  • 285,553
  • 42
  • 434
  • 765
0

A) See Turning an ExecutorService to daemon in Java. Daemon threads will technically answer stated question (no requirement to poll a "shutdown" variable) but are probably a bad idea in any stateful context as the thread will be stopped in the middle of operation with no warning by the JVM (as soon as all non-daemon threads complete).

executorService = Executors.newFixedThreadPool(2, r -> {
            Thread t = Executors.defaultThreadFactory().newThread();
            t.setDaemon(true);
            return t;
        });

B) Another option in the real world (where an idle thread is likely blocking/sleeping on something) is to check shutdown only upon the InterruptedException which will occur upon executorService.shutdownNow()

drekbour
  • 2,895
  • 18
  • 28