2
votes

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
If you are using a thread pool (executor service), you probably don't want to kill the thread but to cancel the task. You can do that by using future.get() with a timeout - you can call that from a separate thread or thread pool if you need to wait asynchronously. - assylias
Re, "...implications of doing that." Threads communicate by accessing shared variables. If the thread that you want to kill has to temporarily put any shared variables into any kind of inconsistent/invalid/nonsensical state in order to do its work (i.e., if there's any reason why the thread ever has to lock a lock), then killing the thread could leave those variables in an inconsistent/invalid/nonsensical state. Also, in some programming systems (I forget about Java) it could also leave the lock permanently locked. - Solomon Slow

1 Answers

0
votes

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