Execute a method after a certain amount of time using ExecutorService - java

I have the following code:
ExecutorService executor = Executors.newSingleThreadExecutor()
Future<String> future = executor.submit(new Callable<String>() {
#Override
String call() throws Exception {
stream.filter(fq)
return null
}
})
try {
future.get(4, TimeUnit.MINUTES)
}
Once the 4 minutes are over I want to execute another method. Where would I put this code?

Catch the TimeoutException and put your code in the catch block.
try {
future.get(4, TimeUnit.MINUTES)
} catch(TimeoutException e) {
//call your method code here, it will be called only if the operation times out
myMethod();
}

Related

Async API using Future never completes [duplicate]

This question already has answers here:
FutureTask get vs run, task never finishes
(3 answers)
Closed 9 months ago.
I try to make an API aysnchronous as:
Future<Integer> fASync(int x) {
return new FutureTask(() -> {
try {
Thread.sleep(new Random().nextInt(1, 3) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return x * x;
});
}
..then I try to use it:
Future<Integer> asyncCall = fASync(x);
asyncCall .get();
But this never completes and call just blocks.
Is this not correct way of making your API asynchronous?
You have declared a FutureTask but haven't actually run it so a call to asyncCall.get() will block forever.
Here is your example with extra logging and adding a step to execute the task in a new ExecutorService.
static FutureTask<Integer> fASync(int x) {
System.out.println("fASync("+x+") called");
return new FutureTask<>(() -> {
System.out.println("fASync("+x+") FutureTask has started");
try {
Thread.sleep(new Random().nextInt(1, 3) * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("fASync("+x+") FutureTask has ended");
return x * x;
});
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService exec = Executors.newFixedThreadPool(1);
FutureTask<Integer> task = fASync(5);
// MUST execute the task or task.get() will block forever
exec.execute(task);
System.out.println("task.get()="+task.get());
exec.shutdown();
exec.awaitTermination(1, TimeUnit.DAYS);
System.out.println("ENDED");
}
If you enable the exec.execute(task); line it will print these messages and complete task.get(), instead of printing the first line only and no response from task.get():
fASync(5) called
fASync(5) FutureTask has started
fASync(5) FutureTask has ended
task.get()=25
ENDED

Shutdown now on ExecutionException

I read a lot of post about ExecutorService, but I can't find the way of doing what I need.
I need some concurrent threads. When any of them throw a custom exception all the remaining tasks are canceled.
This is an example of what I did. The task are working concurrent, but aren't interrupted on exception.
public class Main {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
List<Future> futures = new ArrayList<Future>();
futures.add(executorService.submit(new Callable<Void>() {
public Void call() throws Exception {
Thread.sleep(5000);
System.out.println("Task 1 done");
return null;
}
}));
futures.add(executorService.submit(new Callable<Void>() {
public Void call() throws Exception {
Thread.sleep(2000);
System.out.println("Task 2 done");
if (true) {
throw new CustomException("Error on task 2");
}
return null;
}
}));
executorService.shutdown();
try {
executeFutures(futures);
} catch (CustomException ex) {
System.out.println("Received:" + ex.getMessage());
executorService.shutdownNow();
}
}
private static void executeFutures(List<Future> futures) throws CustomException {
try {
for (Future f : futures) {
f.get();
}
} catch (ExecutionException | InterruptedException e) {
if (e.getCause() instanceof CustomException) {
throw (CustomException) e.getCause();
}
}
}
}
This is the output:
Task 2 done //exception is thrown here but task1 continue.
Task 1 done
Received:Error on task 2
Any help will be appreciated.
Your problem is due to the fact that the method executeFutures make the main thread call f.get() on the first Future instance corresponding to the long task, which makes it wait the duration of the task so at least 5 seconds whatever happens. Once done it will then call f.get() on the second Future which is already over so it gets immediately the CustomException from the ExecutionException and calls executorService.shutdownNow() but it is already too late as there is no more tasks left to interrupt.
What you could do, is to use a decorator of type Callable that will automatically shutdown the thread pool when a CustomException is thrown, this way the thread pool will be shutdown directly by the thread that has executed the task that throws the exception instead of using the main thread.
Something like this:
public class AutoShutdown<V> implements Callable<V> {
private final ExecutorService executorService;
private final Callable<V> task;
public AutoShutdown(final ExecutorService executorService, final Callable<V> task) {
this.executorService = executorService;
this.task = task;
}
#Override
public V call() throws Exception {
try {
return task.call();
} catch (CustomException e) {
executorService.shutdownNow();
throw e;
}
}
}
Then you will need to submit your tasks through the decorator as next:
futures.add(
executorService.submit(
new AutoShutdown<>(
executorService,
new Callable<Void>() {
public Void call() throws Exception {
Thread.sleep(5000);
System.out.println("Task 1 done");
return null;
}
}
)
)
);
futures.add(
executorService.submit(
new AutoShutdown<>(
executorService,
new Callable<Void>() {
public Void call() throws Exception {
Thread.sleep(2000);
System.out.println("Task 2 done");
if (true) {
throw new CustomException("Error on task 2");
}
return null;
}
}
)
)
);
Output:
Task 2 done
As you can see in the output, the task one has been interrupted soon enough.
The message "Received:Error on task 2" was not thrown, so it looks
like a successful execution, and is not the case
No it is only because the first call to f.get() throws an InterruptedException as expected which makes it exit from executeFutures because the catch is performed outside the loop, move it inside the loop as next:
private static void executeFutures(List<Future> futures) throws CustomException {
for (Future f : futures) {
try {
f.get();
} catch (ExecutionException | InterruptedException e) {
if (e.getCause() instanceof CustomException) {
throw (CustomException) e.getCause();
}
}
}
}
Output:
Task 2 done
Received:Error on task 2

Execute a continious task via ThreadPoolExecutor

Facing the problem with the ThreadPoolExecutor in Java.
How can I execute a continuous task using it? For example, I want to execute something like this:
#Async
void MyVoid(){
Globals.getInstance().increment();
System.out.println(Thread.currentThread().getName()+" iteration # "+ Globals.getInstance().Iterator);
}
I want it to run forever in 2 parallel asynchronous threads until the user sends a request to stop the ThreadPoolExecutor in the "/stop" controller.
If I use this for example:
#Controller
#RequestMapping("api/test")
public class SendController {
ThreadPoolExecutor executor = new ErrorReportingThreadPoolExecutor(5);
boolean IsRunning = true;
#RequestMapping(value = "/start_new", method = RequestMethod.POST)
public Callable<String> StartNewTask(#RequestBody LaunchSend sendobj) throws IOException, InterruptedException {
Runnable runnable = () -> { MyVoid();};
executor.setCorePoolSize(2);
executor.setMaximumPoolSize(2);
while (IsRunning) {
executor.execute(runnable);
System.out.println("Active threads: " + executor.getActiveCount());
}
return () -> "Callable result";
}
#RequestMapping(value = "/stop", method = RequestMethod.GET)
public Callable<String> StopTasks() {
executor.shutdown(); //for test
if(SecurityContextHolder.getContext().getAuthentication().getName() != null && SecurityContextHolder.getContext().getAuthentication().getName() != "anonymousUser") {
executor.shutdown();
return () -> "Callable result good";
}
else { return () -> "Callable result bad";}
}
}
public class ErrorReportingThreadPoolExecutor extends ThreadPoolExecutor {
public ErrorReportingThreadPoolExecutor(int nThreads) {
super(nThreads, nThreads,
0, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
#Override
protected void afterExecute(Runnable task, Throwable thrown) {
super.afterExecute(task, thrown);
if (thrown != null) {
// an unexpected exception happened inside ThreadPoolExecutor
thrown.printStackTrace();
}
if (task instanceof Future<?>) {
// try getting result
// if an exception happened in the job, it'll be thrown here
try {
Object result = ((Future<?>)task).get();
} catch (CancellationException e) {
// the job get canceled (may happen at any state)
e.printStackTrace();
} catch (ExecutionException e) {
// some uncaught exception happened during execution
e.printStackTrace();
} catch (InterruptedException e) {
// current thread is interrupted
// ignore, just re-throw
Thread.currentThread().interrupt();
}
}
}
}
I'm getting the following errors:
As I understood, a lot of tasks got submitted into the 'executor' queue within a few seconds and then the executor handled all them. (But I need each thread to wait before the current task ends and then submit the new one to the executor, I think.)
HTTP Requests to these controllers are forever "IDLE" until the next request comes, i.e. after sending a request to /api/test/start_new the controller's code executed tasks that are running, but the request is IDLE.
How can I do this in Java?
P.S. Spring MVC is used in the project. It has its own implementation of ThreadPoolExecutor - ThreadPoolTaskExecutor, but I am facing similar problems with it.

JUnit for future.get() Exception scenario

I need to test InterruptedException and ExecutionException and write JUnits for the same.
Please advice me on this. How can i interrupt the threads to replicate the scenario. The populateDataForm will start new threads and add this to futures list.
Here is my sample code:
class MyTest{
public populateData(){
Collection<Future<?>> futures = new LinkedList<Future<?>>();
DataSet ds = Helper.populateDataForm(employee, futures);
waitForTaskCompletion(futures);
}
private waitForTaskCompletion(futures){
for (Future<?> future:futures) {
try {
future.get();
} catch (InterruptedException e) {
throw new CustomExcpetion("Message1", e)
} catch (ExecutionException e) {
throw new CustomExcpetion("Message2", e)
}
}
}
You can inherit from MyTest and overload populateData() method as follows:
public void populateData() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<String> calls = new Callable<String>() {
#Override
public String call() throws Exception {
for (;;){
Thread.sleep(100);
// You call interrupt here, which causes Future.get() interrupt
Thread.currentThread().interrupt();
if (1 > 2) break;
}
return null;
}
};
final Future<String> future = executorService.submit(calls);
waitForTaskCompletion(future);
executorService.shutdown();
}
To test the ExecutionException throw RuntimeException instead of the interrupt as follows:
if (1==1)throw new RuntimeException();

Java/ test & operation after timeout

I hava a test, with:
#test(timeout = 50000)
I want to do some operations if the test fails because the timeout, and only then.
I try the next:
#Test(timeout=60000)
public void test1() {
try{
// code
}
catch(Exception e){
//operations after time out
}
}
But it doesn't work. Any help?
It's not possible to do what you described here with JUnit's timeout parameter because it doesn't provide a callback to handle the operations after it has timed out.
But, you can certainly write your own test harness to do just that. In the below example, I want the code to execute within one second but my actual code execution takes 2 seconds. In this case, we catch the TimeoutException and you can perform your additional operation within that catch block.
#Test
public void testMe() {
// test must finish within one second
int expectedExecutionInSeconds = 1;
RunnableFuture<String> runnableFuture = new FutureTask<String>(new Callable<String>() {
public String call() throws Exception {
// your actual code goes in here
Thread.sleep(2000);
return "ok";
}
});
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(runnableFuture);
try {
String result = runnableFuture.get(expectedExecutionInSeconds, TimeUnit.SECONDS);
assertEquals("ok", result);
}
catch (TimeoutException ex) {
// stop code
runnableFuture.cancel(true);
System.out.println("do other stuff");
}
catch (Exception e) {
fail("other stuff is failing");
}
executorService.shutdown();
}

Categories