I would like to wait for a condition asynchronously. Below is an example using awaitility library however, as far as I know, awaitility is blocking (i.e not async). Any ideas on how to achieve this in an async way natively (or with another lib maybe). Any ideas are appreciated.
await().forever().with().pollInterval(1, TimeUnit.SECONDS)
.until(() -> redis.eval(lockscript, ScriptOutputType.BOOLEAN, "mutex:" + key).equals(true));
await().atMost(timeout, TimeUnit.SECONDS).with().pollInterval(1, TimeUnit.SECONDS).until(
() -> redis.eval(lockscript, ScriptOutputType.BOOLEAN, "mutex:" + key).equals(true));
As mentioned in the comments, you can play around with Completable Futures and a Scheduled Executor to get what you want (or at least something close to that).
We can define a method until like so:
public void until(Callable<Boolean> method, long timeout, TimeUnit unit, ScheduledExecutorService s) throws Exception {
s.scheduleAtFixedRate(() -> {
try {
Boolean returnVal = method.call();
if (returnVal == true)
s.shutdown();
} catch (Exception e) {
e.printStackTrace();
}
}, timeout, timeout, unit);
}
What this does is take a passed scheduledExecutor and invoke any Callable method (in this case with a return value Boolean since this is what you want. This will loop every timeout until the requirement is met and the scheduler is shutdown.
Note: If you want to re-use the scheduler, do not call shutdown() on it, but rather cancel().
The way we call this is as follows:
ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
until(() -> basicBoolStatement(), 1, TimeUnit.SECONDS, sched);
We don't need the scheduler to have more than one thread. Just pass in anything else that returns a boolean for basicBoolStatement().
If you want to give a time limit to your request, then you can do the additional call, like so:
public static void untilAtMost(Callable<Boolean> method, long untilTimeout, long atMostTimeout, TimeUnit unit, ScheduledExecutorService s) throws Exception {
CompletableFuture.runAsync(() -> {
try {
until(method, untilTimeout, unit, s);
} catch (Exception e) {
e.printStackTrace();
}
});
ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
sched.schedule(() -> {
s.shutdown();
sched.shutdown();
}, atMostTimeout, unit);
}
Here, we re-use the until method above, but we have another scheduler that will shutdown() the until scheduler when the atMostTimeout time passes.
And in the same way, the calling code would look something like:
ScheduledExecutorService sched = new ScheduledThreadPoolExecutor(1);
untilAtMost(() -> basicBoolStatement(), 10, 1, TimeUnit.SECONDS, sched);
Edit: If you don't want to handle exceptions the way it is with the Callable interface, you can use a Supplier.
Disclaimer: sorry for the messy code, but this is just a proof of concept.
Related
We used multiple thread groups in projects for parallel execution like below
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
Here my question is how to terminate other thread groups when exception comes in any one of the thread group.
thanks.
One option is to have a separate service which
tracks the relevant threadpools
tracks an exception flag
you delegate task submission to so it can wrap Runnables in a try-catch which sets the exception flag to true
periodically checks if the exception flag is true and, if so, attempts to shutdown all relevant threadpools
For example you could have something like below.
public class ThreadpoolService {
private final AtomicBoolean threadpoolException = new AtomicBoolean(false);
private final Set<ExecutorService> threadPools = new HashSet<>();
private final ScheduledExecutorService tracker = Executors.newSingleThreadScheduledExecutor();
public ThreadpoolService() {
// Start a thread tracking if an exception occurs in the threadpools, and if so attempts to shut them down
tracker.scheduleAtFixedRate(() -> {
if (threadpoolException.get()) {
shutdownThreadPools();
}
// Run the tracker every second, with an initial delay of 1 second before the first run
}, 1000, 1000, TimeUnit.MILLISECONDS);
}
private void shutdownThreadPools() {
// For each threadpool create a completable future which attempts to shut it down
final var threadpoolStopTasks = threadPools.stream()
.map(tp -> CompletableFuture.runAsync(() -> {
try {
tp.shutdown();
// Await termination, force if taking too long
if (!tp.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
tp.shutdownNow();
}
} catch (InterruptedException e) {
tp.shutdownNow();
Thread.currentThread().interrupt();
}
}))
.collect(Collectors.toList());
// Create a completable future from all of the above stop tasks, wait for it to complete then
// stop the executor this tracker is running in
CompletableFuture.allOf(threadpoolStopTasks.toArray(new CompletableFuture[0]))
.thenApply((v) -> {
tracker.shutdownNow();
return null;
})
.join();
}
public void submit(ExecutorService threadPool, Runnable task) {
threadPools.add(threadPool);
threadPool.submit(() -> {
try {
task.run();
} catch (Exception e) {
// do stuff
threadpoolException.set(true);
}
});
}
public void shutdown() throws InterruptedException {
shutdownThreadPools();
tracker.shutdown();
if (!tracker.awaitTermination(1000, TimeUnit.MILLISECONDS)) {
tracker.shutdownNow();
}
}
}
Then in your program
final var threadpoolService = new ThreadpoolService();
// Then wherever you use a threadpool delegate to the above for task submissing
final var tp1 = Executors.newFixedThreadPool(5);
threadpoolService.submit(tp1, () -> {
// some task which may fail exceptionally
return;
});
When your program needs to shutdown for some other reason
threadpoolService.shutdown();
}
Of note is that an exception triggerring the shutdown of these threadpools is not recoverable i.e. the threadpools and ThreadpoolService are no longer in a functional state after shutdown and really, this should trigger the end of the program - you could enhance this to register a shutdown hook which ends the program.
It should also be noted that I've made a lot of assumptions inc.
use of the default fork-join pool for CompletableFutures (you can just pass your own executor service)
expectation the CompletableFuture.allOf will finish in a timely manner (you can add a timeout)
hardcoded time intervals (you can make these configurable)
It also doesn't cover the below, both of which can be resolved by using a guard (maybe threadpoolException) on appropriate methods and returning some value or throwing an exception as appropriate
race conditions on the various methods (e.g. calling shutdown while a shutdown is in progress)
calling submit following a shutdown
I have a task that I want to run at a fixed rate. However I also need the result of the task after each execution. Here is what I tried:
The task
class ScheduledWork implements Callable<String>
{
public String call()
{
//do the task and return the result as a String
}
}
No I tried to use the ScheduledExecutorService to scheduled it. Turns out you cannot schedule a Callable at a fixed rate, only a Runnable can be done so.
Please advise.
Use a producer/consumer pattern: Have the Runnable put its result on a BlockingQueue. Have another thread take() from the queue.
Take is a blocking call (ie only returns when something is on the queue), so you'll get your results as soon as they're available.
You could combine this with the hollywood pattern to provide the waiting thread with a callback so your code gets called when something is available.
Unless if you don't care about the return value of your Callable, you can wrap it in a Runnable and use that to pass to ScheduledExecutorService.
public static Runnable runnableOf(final Callable<?> callable)
{
return new Runnable()
{
public void run()
{
try
{
callable.call();
}
catch (Exception e)
{
}
}
};
}
Then when you want to submit to ScheduledExecutroService you can pass your Callable:
ses.scheduleAtFixedRate(runnableOf(callabale), initialDelay, delay, unit);
I have several async methods (Annotatad #Asynchronous) Returning Future Objects. I have to execute them at once but it would be enough for me to get the result of the first one which ready, is there any nice and safe solutions for that that works on a Java EE container?
Thanks!
There's no standard API for this facility. Just check Future#isDone() yourself in an infinite loop on the current thread in an utility method which look like below:
public static <T> Future<T> getFirstDone(List<Future<T>> futures) {
while (true) {
for (Future<T> future : futures) {
if (future.isDone()) {
return future;
}
}
// Break if necessary infinite loop here once it reaches certain timeout.
}
}
Usage:
List<Future<Foo>> results = collectThemSomehow();
Future<Foo> firstDoneResult = getFirstDone(results);
// ...
Here is an example of how it can works with Spring. In this example, the asynchronous job simply returns a boolean.
public void example(Job job) throws Exception
{
Future<Boolean> executor = jobExecutor.doJob(job);
//wait to be done
while (!executor.isDone()) {
Thread.sleep(10);
}
System.out.println(executor.get());
}
The job executor class is annoted #Component.
#Async
public Future<Boolean> doJob(Job job) throws Exception {
boolean isSuccessful;
//do something
return new AsyncResult<Boolean>(isSuccessful);
}
Sometimes you can invert it - transfer function pointer to async method and call it:
AtomicBoolean executed = new AtomicBoolean(false);
Runnable r = () ->{
if(!executed.getAndSet(true)){
//do job
}
};
But be careful: this code is executed inside worker thread, not original thread.
In java, I have ExecutorService that runs with while true, and Throwable catch clouse. I find out that from time to time the thread goes down. That means the system stop function.
So my question is, first of all, how can I catch the "thread killed" event (in order to send me email on such case)?
Also, how can this thread goes down?
the code is:
ExecutorService changesTrackerThread = Executors.newSingleThreadExecutor();
changesTrackerThread.submit(queueUpdater());
private Runnable queueUpdater() {
return new Runnable() {
#Override
public void run() {
while (true)
{
try
{
// do some code, then sleep
Thread.sleep(2000L);
} catch (Throwable t)
{
_log.error("something bad happened, but the loop should keep running", t);
}
}
}
};
Well first of all, why are you using a while loop here!?
You should use a scheduled executor:
ExecutorService changesTrackerThread = Executors.newSingleThreadScheduledExecutor()();
changesTrackerThread.scheduleAtFixedRate(new queueUpdater(), 0, 2, TimeUnit.SECONDS);
private Runnable queueUpdater() {
return new Runnable() {
#Override
public void run() {
try
{
// do some code
} catch (Throwable t)
{
_log.error("something bad happened", t);
}
}
};
I do not know why your thread dies, show us the full code.
But this way even if the thread dies the Excecutor will rerun it after the given period(2 seconds in this example.
As others have noted, you could replace your while (true) and sleep() loop with a ScheduledExecutorService. Scheduling a repeating task on such a service will return a ScheduledFuture which you can use to check the status of this task or to cancel it if you have a need for that. This will enable you to remove the try/catch block from the code.
Start the service like this:
ScheduledExecutorService svc = Executors.newScheduledThreadPool(1);
I would use newScheduledThreadPool() instead of newSingleThreadScheduledExecutor() since the former will restart threads if necessary.
Then, schedule the work like this:
void doSomeCode() {
// do some code
}
ScheduledFuture<?> sf = svc.scheduleAtFixedRate(this::doSomeCode, 0L, 2L, TimeUnit.SECONDS);
(Or if you wish you can inline doSomeCode() as a lambda or an anonymous inner class.)
Now what happens if the task fails with an exception? The ScheduledFuture object returned allows you to check status in a variety of ways. If you have a thread that you can dedicate to waiting for failures, you can have it call sf.get() which will throw an ExecutionException that wraps the exception that caused the task to fail. Otherwise, it blocks indefinitely. ScheduledFuture.get() is a bit weird in that unlike an ordinary Future.get() call, it never returns a value; it always throws an exception.
When/if the task fails, the caller of sf.get() can log the exception and resubmit the task, or whatever. If you don't want to block a thread indefinitely, you can poll for failure using sf.isDone() or sf.get(0L, TimeUnit.SECONDS). Note that both overloads of sf.get() communicate all of their return information via the type of a thrown exception, which may make them somewhat inconvenient to use.
You could put exception handling within the task itself, catching Throwable and continuing no matter what, and this will probably work. It does bake the logging/restart/resubmission policy into the task itself, which may be unpleasant. Using ScheduledFuture lets you separate these policies from the actual work performed by the task.
I am confused with the following.
I know, if I use the schedule method from the ScheduledThreadPoolExecutor class:
ScheduledFuture<?> scheduledFuture =
scheduledThreadPoolExecutor.schedule(myClassRunnable, 5, TimeUnit.SECONDS);
I am able to retrieve later the value through
scheduledFuture.get(5, TimeUnit.SECONDS) or scheduledFuture.get() and it should be null because the task has been executed just only once and it is completed.
And null because I am working with the Runnable schedule method version and not with the Callable schedule method version. It according with the API.
Until here I am fine.
My question:
What is the purpose of ScheduledFuture if is retrieved from the scheduleWithFixedDelay (even from scheduleAtFixedRate) method:
ScheduledFuture<?> scheduledFuture=
scheduledThreadPoolExecutor.scheduleWithFixedDelay(myClassRunnable, 1, 5, TimeUnit.SECONDS);
Yes, I know both fixed methods execute the same task many times until the ScheduledThreadPoolExecutor's shutdown method is called (it must stop all the tasks scheduled).
I did a research through Google looking for some examples using ScheduledFuture returned from scheduleWithFixedDelay, I only found one using the cancel method, to cancel a specific task. But none working with get().
I don't know if I am wrong, but seems useless the get() method if we are working with scheduleWithFixedDelay, because if I use later:
scheduledFuture.get() - it remains awaiting and the Runnable object remains working many times (run,complete,delay,run,etc... )
scheduledFuture.get(32, TimeUnit.SECONDS) - always gives a TimeoutException
I thought I should be able to retrieve the null value since I can use the period argument/parameter from the scheduleWithFixedDelay method. I.e: Run the Runnable object, wait until it completes and use the scheduledFuture.get() to get the null value that confirms it has been completed, await the period of the delay time to run again the Runnable object according with the period value etc....
Clarifications and examples are totally welcome.
ScheduledFuture can be used to get time left before next task execution:
ScheduledFuture<?> f = Executors.newScheduledThreadPool(1).scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println("run");
}
}, 0, 10000, TimeUnit.MILLISECONDS);
Thread.sleep(1000);
System.out.println("Time left before next run " + f.getDelay(TimeUnit.MILLISECONDS));
prints
run
Time left before next run 8999
I tried this out with the following code:
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
AtomicInteger count = new AtomicInteger(0);
Runnable task = () -> {
int currentCount = count.incrementAndGet();
System.out.println("Task #" + currentCount + " started");
if (currentCount == 2) {
System.out.println("Shutting down scheduler...");
scheduler.shutdown();
}
try {
Thread.sleep(1000);
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
System.out.println("Task #" + currentCount + " finished");
};
System.out.println("Starting scheduler...");
ScheduledFuture<?> scheduledFuture = scheduler.scheduleWithFixedDelay(
task, 0, 2, TimeUnit.SECONDS);
System.out.println("Getting scheduled future...");
System.out.println(scheduledFuture.get());
System.out.println("End of code reached.");
Here is the output:
Exception in thread "main" java.util.concurrent.CancellationException
at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:121)
at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191)
at Rextester.main(source.java:33)
Starting scheduler...
Getting scheduled future...
Task #1 started
Task #1 finished
Task #2 started
Shutting down scheduler...
Task #2 finished
Online Rextester Demo: https://rextester.com/LYKN32123
Not sure how useful this is but it shows the get() method throws a CancellationException if the scheduler is shut down.
I would think that in the case of using .scheduleWithFixedDelay(...) (or scheduleAtFixedRate(...)), the get() method of the returned ScheduledFuture<?> feels indeed as an odd fit.
I believe you won't ever receive anything from the get() method, just expect an exception to be thrown from it, when Runnable is cancelled.
Surely one can see a use-case for this ;-)
see JavaDoc
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleAtFixedRate-java.lang.Runnable-long-long-java.util.concurrent.TimeUnit-
Returns:
a ScheduledFuture representing pending completion of the task, and whose get() method will throw an exception upon cancellation
You can't catch the exception thrown by the submitted task without calling get.
Suppose you have a task like this.
public class Task1 implements Runnable {
private int counter = 3;
#Override
public void run() {
System.out.println("It is called");
counter--;
if (counter == 0) {
throw new RuntimeException(new Exception("It fails"));
}
}
}
No exception is thrown by the following code, so you are not able to handle that.
public static void main(String[] args) throws Exception {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
Task1 task1 = new Task1();
executorService.scheduleAtFixedRate(task1, 0, 2, TimeUnit.SECONDS);
}
However, if you add get to it, then you can catch the exception.
public static void main(String[] args) throws Exception {
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
Task1 task1 = new Task1();
ScheduledFuture<?> future = executorService.scheduleAtFixedRate(task1, 0, 2, TimeUnit.SECONDS);
try {
future.get(); // CAUTION: This line blocks the execution
} catch (ExecutionException e) {
e.printStackTrace();
executorService.shutdown();
}
}
Using scheduledFuture.get() you can get a handle to the task, and in case this task needs to be cancelled say manually from the UserInterface or based on some conditions like the null, the handle can be used to cancel it.