I have infinite queue of promises(completablefuture) as an input.
The goal is to run promises one by one till condition fulfilled on the result and stop processing and return result from current promise.
My iterative solution looks like that:
volatile boolean shouldKeepReading = true;
....
CompletableFuture<Integer> result = promisesQueue.poll().get();
while (shouldKeepReading) {
result = result.thenCompose(res -> {
if (conditionPass(res)) {
shouldKeepReading = false;
return CompletableFuture.completedFuture(0));
} else {
if (shouldKeepReading) {
return promisesQueue.poll().get();
} else {
return CompletableFuture.completedFuture(0));
}
}
});
I used infinite loop with volatile flag to control processing. Volatile guarantee memory visibility to all readers. Once condition met control flag will be set to false in order to stop processing.
I used double check before read next item.
if (shouldKeepReading) {
return promisesQueue.poll().get();
The code seems works correct but noticed that volatile keyword is not needed here, it doesn't change the processing. Why ? Have I miss something ?
Do you see any problems with that code ?
The HotSpot JVM is rather conservative. It’s too easy to reproducibly see writes made by other threads as side effect of other, unrelated, reads and writes with stronger memory guarantees.
For example, in your case thenCompose checks the completion status of the future whereas the implementation specific caller of the function will change the completion status. This may appear to have the desired effect even when the status is “not completed” in which case there’s no formal happens-before relationship or when actually calling thenApply on the next chained future which also doesn’t establish a happens-before relationship as it’s a different variable.
In other words, it may appear to work with this JVM implementation without volatile but is not guaranteed, so you should never rely on such behavior.
Even worse, your code is not guaranteed to work even with volatile.
The basic shape of your code is
CompletableFuture<Integer> result = …
while (shouldKeepReading) {
result = result.thenCompose(…);
}
which implies that as long as the initial future is not already completed, this loop may chain an arbitrary number of dependent actions until the completion of the dependency chain manages to catch up. The system load caused by this loop may even prevent the chain from catching up, until encountering an OutOfMemoryError.
As long as the completion chain manages to catch up, you don’t notice a difference, as all chained actions evaluate to the same result, zero, as soon as shouldKeepReading became false.
Since the original future originates from promisesQueue.poll().get() outside the scope, we may simulate a higher workload by inserting a small delay. Then, add a counter to see what the end result doesn’t tell, e.g.
AtomicInteger chainedOps = new AtomicInteger();
CompletableFuture<Integer> result = promisesQueue.poll().get();
result = result.whenCompleteAsync(
(x,y) -> LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)));
while(shouldKeepReading) {
result = result.thenCompose(res -> {
chainedOps.incrementAndGet();
if(conditionPass(res)) {
shouldKeepReading = false;
return CompletableFuture.completedFuture(0);
} else {
if (shouldKeepReading) {
return promisesQueue.poll().get();
} else {
return CompletableFuture.completedFuture(0);
}
}
});
}
result.join();
System.out.println(chainedOps.get() + " chained ops");
On my machine, the loop easily chains more than five million actions, even when conditionPass returns true in the first.
The solution is quite simple. Use neither a flag variable nor a loop
result = result.thenCompose(new Function<Integer, CompletionStage<Integer>>() {
#Override
public CompletionStage<Integer> apply(Integer res) {
// for testing, do chainedOps.incrementAndGet();
return conditionPass(res)? CompletableFuture.completedFuture(0):
promisesQueue.poll().get().thenCompose(this);
}
});
This calls thenCompose only when the condition is not fulfilled, hence, never chains more actions than necessary. Since it requires the function itself to be chained via thenCompose(this), the lambda has to be replaced by an anonymous inner class. If you don’t like this, you may resort to a recursive solution
CompletableFuture<Integer> retryPoll() {
CompletableFuture<Integer> result = promisesQueue.poll().get();
return result.thenComposeAsync(res ->
conditionPass(res)? CompletableFuture.completedFuture(0): retryPoll());
}
It’s remarkably simple here, as the retry doesn’t depend on the result of the previous evaluation (you’d need to introduce parameters otherwise), but on the changes promisesQueue.poll().get() makes to the program’s state.
This method uses thenComposeAsync to avoid deep recursions if there is a large number of already completed futures whose result is rejected by conditionPass. If you know for sure that conditionPass will succeed after a rather small amount of retries, you can change thenComposeAsync to thenCompose.
Related
I want to create two threads in my application that'll run two methods. I'm using the builder design pattern where inside the build method I have something like this, request is the Object that is passed:
Rules rule;
Request build() {
Request request = new Request(this);
//I want one threat to call this method
Boolean isExceeding = this.rule.volumeExceeding(request);
//Another thread to call this method
Boolean isRepeating = this.rule.volumeRepeating(request);
//Some sort of timer that will wait until both values are received,
//If one value takes too long to be received kill the thread and continue with
//whatever value was received.
..Logic based on 2 booleans..
return request;
}
Here's how this class looks like:
public class Rules {
public Boolean volumeExceeding(Request request) {
...some...logic...
return true/false;
}
public Boolean volumeRepeating(Request request) {
...some...logic...
return true/false;
}
}
I have commented in the code what I'd like to happen. Basically, I'd like to create two threads that'll run their respective method. It'll wait until both are finished, however, if one takes too long (example: more than 10ms) then return the value that was completed. How do I create this? I'm trying to understand the multithreading tutorials, but the examples are so generic that it's hard to take what they did and apply it to something more complicated.
One way to do that is to use CompletableFutures:
import java.util.concurrent.CompletableFuture;
class Main {
private static final long timeout = 1_000; // 1 second
static Boolean volumeExceeding(Object request) {
System.out.println(Thread.currentThread().getName());
final long startpoint = System.currentTimeMillis();
// do stuff with request but we do dummy stuff
for (int i = 0; i < 1_000_000; i++) {
if (System.currentTimeMillis() - startpoint > timeout) {
return false;
}
Math.log(Math.sqrt(i));
}
return true;
}
static Boolean volumeRepeating(Object request) {
System.out.println(Thread.currentThread().getName());
final long startpoint = System.currentTimeMillis();
// do stuff with request but we do dummy stuff
for (int i = 0; i < 1_000_000_000; i++) {
if (System.currentTimeMillis() - startpoint > timeout) {
return false;
}
Math.log(Math.sqrt(i));
}
return true;
}
public static void main(String[] args) {
final Object request = new Object();
CompletableFuture<Boolean> isExceedingFuture = CompletableFuture.supplyAsync(
() -> Main.volumeExceeding(request));
CompletableFuture<Boolean> isRepeatingFuture = CompletableFuture.supplyAsync(
() -> Main.volumeRepeating(request));
Boolean isExceeding = isExceedingFuture.join();
Boolean isRepeating = isRepeatingFuture.join();
System.out.println(isExceeding);
System.out.println(isRepeating);
}
}
Notice that one task takes significantly longer than the other.
What's happening? You supply those tasks to the common pool by using CompletableFuture for execution. Both tasks are executed by two different threads. What you've asked for is that a task is stopped when it takes too long. Therefore you can simply remember the time when a task has started and periodically check it against a timeout. Important: Do this check when the task would return while leaving the data in a consistent state. Also note that you can place multiple checks of course.
Here's a nice guide about CompletableFuture: Guide To CompletableFuture
If I understand your question correctly, then you should do this with a ticketing system (also known as provider-consumer pattern or producer-consumer pattern), so your threads are reused (which is a significant performance boost, if those operations are time critical).
The general idea should be:
application initialization
Initialize 2 or more "consumer" threads, which can work tickets (also called jobs).
runtime
Feed the consumer threads tickets (or jobs) that will be waited on for (about) as long as you like. However depending on the JVM, the waiting period will most likely not be exactly n milliseconds, as most often schedulers are more 'lax' in regards to waiting periods for timeouts. e.g. Thread.sleep() will almost always be off by a bunch of milliseconds (always late, never early - to my knowledge).
If the thread does not return after a given waiting period, then that result must be neglected (according to your logic), and the ticket (and thus the thread) must be informed to abort that ticket. It is important that you not interrupt the thread, since that can lead to exceptions, or prevent locks from being unlocked.
Remember, that halting or stopping threads from the outside is almost always problematic with locks, so I would suggest, your jobs visit a possible exit point periodically, so if you stop caring about a result, they can be safely terminated.
I am using a proprietary, 3rd party framework in my Android app -- EMDK from Zebra, to be specific -- and two of their exposed methods:
.read() and .cancelRead() are asynchronous, each taking anywhere from a split second to a 5 whole seconds to complete. I need to be able to spam them without crashing my application and ensure that each one isn't called twice in a row. How can I go about doing this? I don't have any access to the methods themselves and a decompiler will only give me runtime stubs.
Edit: I also have no idea when each of these two calls ever completes.
Changing asynchronous programs into blocking ones is a more general requirement to this problem.
In Java, we can do this with CountDownLatch (as well as Phaser), or LockSupport + Atomic.
For example, if it is required to change an asynchronous call asyncDoSomethingAwesome(param, callback) into a blocking one, we could write a "wrapper" method like this:
ResultType doSomethingAwesome(ParamType param) {
AtomicReference<ResultType> resultContainer = new AtomicReference<>();
Thread callingThread = Thread.currentThread();
asyncDoSomethingAwesome(param, result -> {
resultContainer.set(result);
LockSupport.unpark(callingThread);
});
ResultType result;
while ((result = resultContainer.get()) == null) {
LockSupport.park();
}
return result;
}
I think this will be enough to solve your problem. However, when we are writing blocking programs, we usually want a "timeout" to keep the system stable even when an underlying interface is not working properly, for example:
ResultType doSomethingAwesome(ParamType param, Duration timeout) throws TimeoutException {
AtomicReference<ResultType> resultContainer = new AtomicReference<>();
Thread callingThread = Thread.currentThread();
asyncDoSomethingAwesome(param, result -> {
resultContainer.set(result);
LockSupport.unpark(callingThread);
});
ResultType result;
long deadline = Instant.now().plus(timeout).toEpochMilli();
while ((result = resultContainer.get()) == null) {
if (System.currentTimeMillis() >= deadline) {
throw new TimeoutException();
}
LockSupport.parkUntil(deadline);
}
return result;
}
Sometimes we need more refined management to the signal among threads, especially when writing concurrency libries. For example, when we need to know whether the blocking thread received the signal from another thread calling LockSupport.unpark, or whether that thread successfully notified the blocking thread, it is usually not easy to implement with Java standard library. Thus I designed another library with more complete mechanism to solve this issue:
https://github.com/wmx16835/experimental_java_common/blob/master/alpha/src/main/java/mingxin/wang/common/concurrent/DisposableBlocker.java
With the support of DisposableBlocker, life will become much easier :)
ResultType doSomethingAwesome(ParamType param, Duration timeout) throws TimeoutException {
// We can use org.apache.commons.lang3.mutable.MutableObject instead of AtomicReference,
// because this object will never be accessed concurrently
MutableObject<ResultType> resultContainer = new MutableObject<>();
DisposableBlocker blocker = new DisposableBlocker();
asyncDoSomethingAwesome(param, result -> {
resultContainer.setValue(result);
blocker.unblock();
});
if (!blocker.blockFor(timeout)) {
throw new TimeoutException();
}
return resultContainer.getValue();
}
Might be off on this as I'm not 100% sure what you're trying to achieve/nor the structure, but could you wrap each in an AsyncTask? Then in a parent AsyncTask or background thread:
AsyncTask1.execute().get(); //get will block until complete
AsyncTask2.execute().get(); //get will block until complete
This is assuming there is some way of knowing the calls you're making completed.
Reading this code AsyncSubscriber.java :
The coder uses AtomicBoolean to create a Happens Before relationships, i want to know :
1_ Is it equivalent to use a synchronized block ?
it looks that the lines
if (on.get()) dosn't ensure that the block
try {
final Signal s = inboundSignals.poll(); // We take a signal off the queue
if (!done) { // If we're done, we shouldn't process any more signals, obeying rule 2.8
// Below we simply unpack the `Signal`s and invoke the corresponding methods
if (s instanceof OnNext<?>)
handleOnNext(((OnNext<T>)s).next);
else if (s instanceof OnSubscribe)
handleOnSubscribe(((OnSubscribe)s).subscription);
else if (s instanceof OnError) // We are always able to handle OnError, obeying rule 2.10
handleOnError(((OnError)s).error);
else if (s == OnComplete.Instance) // We are always able to handle OnComplete, obeying rule 2.9
handleOnComplete();
}
}
will be executed by 1 thread at time.
Indeed when on.get() return true, what prevent another thread from entering the critical section ?!
2_ Is it more efficient than a synchronized block ? (given that AtomicBoolean uses Volatile variable )
here the part of code :
// We are using this `AtomicBoolean` to make sure that this `Subscriber` doesn't run concurrently with itself,
// obeying rule 2.7 and 2.11
private final AtomicBoolean on = new AtomicBoolean(false);
#SuppressWarnings("unchecked")
#Override public final void run() {
if(on.get()) { // establishes a happens-before relationship with the end of the previous run
try {
final Signal s = inboundSignals.poll(); // We take a signal off the queue
if (!done) { // If we're done, we shouldn't process any more signals, obeying rule 2.8
// Below we simply unpack the `Signal`s and invoke the corresponding methods
if (s instanceof OnNext<?>)
handleOnNext(((OnNext<T>)s).next);
else if (s instanceof OnSubscribe)
handleOnSubscribe(((OnSubscribe)s).subscription);
else if (s instanceof OnError) // We are always able to handle OnError, obeying rule 2.10
handleOnError(((OnError)s).error);
else if (s == OnComplete.Instance) // We are always able to handle OnComplete, obeying rule 2.9
handleOnComplete();
}
} finally {
on.set(false); // establishes a happens-before relationship with the beginning of the next run
if(!inboundSignals.isEmpty()) // If we still have signals to process
tryScheduleToExecute(); // Then we try to schedule ourselves to execute again
}
}
}
// What `signal` does is that it sends signals to the `Subscription` asynchronously
private void signal(final Signal signal) {
if (inboundSignals.offer(signal)) // No need to null-check here as ConcurrentLinkedQueue does this for us
tryScheduleToExecute(); // Then we try to schedule it for execution, if it isn't already
}
// This method makes sure that this `Subscriber` is only executing on one Thread at a time
private final void tryScheduleToExecute() {
if(on.compareAndSet(false, true)) {
try {
executor.execute(this);
} catch(Throwable t) { // If we can't run on the `Executor`, we need to fail gracefully and not violate rule 2.13
if (!done) {
try {
done(); // First of all, this failure is not recoverable, so we need to cancel our subscription
} finally {
inboundSignals.clear(); // We're not going to need these anymore
// This subscription is cancelled by now, but letting the Subscriber become schedulable again means
// that we can drain the inboundSignals queue if anything arrives after clearing
on.set(false);
}
}
}
}
3_ Is it safe?
4_ Is it commonly used for this purpose (Creating a Happens Before Relationship) ?
Yes, write/read to AtomicBolean etablishes a happens before relationship:
compareAndSet and all other read-and-update operations such as
getAndIncrement have the memory effects of both reading and writing
volatile variables.
Since you didn't post the entire code and we don't know how exactly this is used it is hard to say if it is thread safe or not, but:
ad 1. it is not equivalent to synchronized block - threads do not wait
ad 2. yes, it could be more efficient, but the compareAndSwap is not obligated to be backed by volatile variable - this is datail of implementation.
ad 3. Hard to say, but the fact that run is a public method exposes some possibility of errors, eg if two threads will invoke the run directly when go will have the value of true. From my perspective it would be better to do compareAndSwap directly in the run method, but I don't know all the requirements, so it is just a suggestion.
ad 4. Yes, AtomicBoolean is commonly used.
Can somebody explain ....This is the official java AtomicBoolean getAndSet method's definition
public final boolean getAndSet(boolean newValue) {
for (;;) {
boolean current = get();
if (compareAndSet(current, newValue))
return current;
}
}
In Java 8, the sourcecode has been slightly restructured, making it easier to understand:
public final boolean getAndSet(boolean newValue) {
boolean prev;
do {
prev = get();
} while (!compareAndSet(prev, newValue));
return prev;
}
As you can see, compareAndSet, which returns a boolean, which comes from the native function Unsafe.compareAndSwapInt, might fail. In that case, the operation is simply repeated.
According to the documentation of Unsafe.compareAndSwapInt,
Atomically update Java variable to x if it is currently holding expected.
Returns:
true if successful
the function will fail if the value of the AtomicBoolean has been changed between calling get() and some point in Unsafe.compareAndSwapInt. This usually shouldn't be the case, but when it happens, it will poll the current value once again and hope the same thing doesn't repeat.
Clearly, it is not an infinite loop. The loop just has its exit condition inside the body:
return current;
In general, this is the typical idiom used in optimistic, lock-free atomic operations. A Compare-And-Swap (CAS) operation is retried until it succeeeds, and it will succeed as soon as it is not contended from another thread. More precisely, the exit condition is met whenever the return value of get() matches the current value as observed by compareAndSet(). It is very hard not to meet this condition, and it happens very rarely.
I have an object that is being initialized in a separate thread. Initialization can take several seconds while a local DB is being populated.
SpecialAnalysis currentAnalysis = new SpecialAnalysis(params_here);
I'm trying to implement a "cancel" button, that sets the object's isCancelled boolean to true. What is the proper Java way to implement this?
while (currentAnalysis == null) {
}
currentAnalysis.cancel();
This method freezes the program as it appears to have entered a computationally inefficient loop. Is this a case where I could use Object.wait()?
My current bad/semi-successful solution is:
while (currentAnalysis == null) {
Thread.sleep(500);
}
currentAnalysis.cancel();
Thanks!
Firstly, yes Object.wait() and Object.notify() / Object.notifyAll() are what you need. Whether or not you use them directly is a different matter. Due to the ease of making mistakes programming directly with wait/notify it is generally recommended to use the concurrency tools added in Java 1.5 (see second approach below).
The traditional wait/notify approach:
Initialisation:
synchronized (lockObject) {
SpecialAnalysis currentAnalysis = new SpecialAnalysis(params_here);
lockObject.notifyAll();
}
In the 'cancel' thread:
synchronized (lockObject) {
while (currentAnalysis == null) {
try { lockObject.wait(); }
catch Exception(e) { } // FIXME: ignores exception
}
}
currentAnalysis.cancel();
Of course these could be synchronized methods instead of blocks. Your choice of lockObject will depend on how many 'cancel' threads you need etc. In theory it could be anything, i.e. Object lockObject = new Object(); as long as you are careful the correct threads have access to it.
Note that it is important to put the call to wait() in a while loop here due to the possibility of spurious wakeups coming from the underlying OS.
A simpler approach would be to use a CountDownLatch, sparing you from the nuts and bolts of wait()¬ify():
(I'm making a couple of assumptions here in order to suggest a possibly cleaner approach).
class AnalysisInitialiser extends Thread {
private CountDownLatch cancelLatch = new CountDownLatch(1);
private SpecialAnalysis analysis = null;
#Override
public void run() {
analysis = new SpecialAnalysis(params);
cancelLatch.countDown();
}
public SpecialAnalysis getAnalysis() {
cancelLatch.await();
return analysis;
}
}
Then in the thread that needs to send the cancel signal: (obviously you need to get hold of the AnalysisInitialiser object in some way)
analysisInit.getAnalysis.cancel();
No concurrency primitive boilerplate, yay!
i like this question so voted up..
you can do like below
do {
if(currentAnalysis != null){
currentAnalysis.cancel();
}
}
while (currentAnalysis == null)
here your do keeps checking the value of currentAnalysis and once its not null then it performs cancel else keeps looping and checking currentAnalysis value.
this is one better approach i am finding right now