How to kill asynchronously running thread after timeout in java 8 and implications of doing that

Viewed 921

I am running an infinite loop and need to achieve the following steps:

  1. check available threads in the executor service (the infinite loop)
  2. fetches the task in the loop.
  3. execute the task in the background(non-blocking) and kill the thread executing the task if it takes more than 3 seconds.

I have looked into the future get API that takes a timeout parameter but not this is blocking in nature.

while(any thread available in thread pool){

Task task = fetchTask();

// somehow execute this task in a non-blocking fashion with a timeout.


}

Is there a way to kill the asynchronously executing threads after the timeout? Will the thread execution will stop and resources will be freed after the timeout?

1 Answers

To achieve this behavior you need this :

  1. Custom class that extends the Thread class and implements the Runnable interface
  2. A Thread Executor to simply have asynchronous execution of threads

The Custom class let us named it 'Task' can have a special implemetation as follow :

import java.util.Date;
import java.util.concurrent.Callable;

public class Task implements Callable<String> {

    private String name;
    private Long elapsedTimeInMillSeconds = 0L;
    static int counter = 0;

    public Task(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    @Override
    public String call() throws Exception {
        Long startTimeInNanoSeconds, endTimeInNanoSeconds;
        startTimeInNanoSeconds = System.nanoTime();
        System.out.println("Executing : " + name + ", Current Seconds : " + new Date().getSeconds());
        counter++;
        System.out.println("Counter = " + counter + " for thread number " + name);
        // Check if our logic is working as expected for Task2 we are going to delay for
        // 7 seconds
        if (counter == 2)
            Thread.sleep(7000);

        endTimeInNanoSeconds = System.nanoTime();
        elapsedTimeInMillSeconds = (endTimeInNanoSeconds - startTimeInNanoSeconds) / 10000;

        System.out
                .println("Thread [ name :  " + name + ", elapsed time  : " + this.elapsedTimeInMillSeconds + " Ms ] ");

        return "" + this.elapsedTimeInMillSeconds;
    }

    public synchronized Long getExecutionTime() {
        return elapsedTimeInMillSeconds;
    }

}

In your Main class try this :

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class Main {
    static final int poolSize = 3;
    static int counter = 1;
    static final ExecutorService executor = Executors.newFixedThreadPool(poolSize);

    public static void main(String[] args) {
        List<Callable<Task>> callableTasks = new ArrayList<>();

        Callable t1 = new Task("Task1");
        Callable t2 = new Task("Task2");
        Callable t3 = new Task("Task3");
        callableTasks.add(t1);
        callableTasks.add(t2);
        callableTasks.add(t3);

        try {

            List<Future<Task>> futures = executor.invokeAll(callableTasks, 3, TimeUnit.SECONDS);
            futures.stream().forEach(Ft -> {

                Ft.cancel(true);
                Task task = null;
                try {
                    task = Ft.get();
                } catch (Exception e) {

                    throw new CancellationException("This Thread has been terminated ");

                }

            });
            executor.shutdownNow();
        } catch (Exception e) {

            if (e instanceof CancellationException) {
                System.out.println("Exception :  " + e.getMessage());

            }

        }
    }

}

The Thread where the counter == 2 is going to be terminated, be cause of our delay

Related