Do something based on result of CompletableFuture without blocking thread in Java - java

First off, I am not really familiar with CompletableFuture. What I am trying to do is retrieve data from a database via CompletableFuture and then do something with the result. Using CompletableFuture#join/get to work with the data is blocking the thread.
CompletableFuture<IPlayerData> future = playerDataManager.getOfflinePlayerDataAsync(target);
IPlayerData result = future.join(); //blocks the thread e.G. if database isn't reachable
//work with the result (maybe callback?)
Note that I am trying to not run the part of code above on a seperate thread. Is there any good way to do this non-blocking? I am pretty sure that there is something wrong with my code (Maybe getOfflinePlayerAsync?) and I really don't know how to continue.
#Override
public CompletableFuture<IPlayerData> getOfflinePlayerDataAsync(OfflinePlayer player) {
CompletableFuture<IPlayerData> future = new CompletableFuture<>();
DiscoBox.schedule(() -> future.complete(handler.loadObject(player.getUniqueId().toString()))).createAsyncTask(); //gets object from database
return future;
}

If you don't want to block the thread that is "receiving" the value, you could do one if the following:
// Get the value if it is available
if (future.isDone()) {
value = future.get();
// do something with value
}
// Get the value if it is available in the next second
try {
value = future.get(1, TimeUnit.SECONDS);
// do something with value
} catch (TimeoutException ex) {
// ho hum
}
With a CompletableFuture, there other non-blocking alternatives; e.g.
value = future.getNow(someDefault);
if (value != someDefault) {
// do something with value
}
Note with all of the above, you are only making one attempt to get the value. If one attempt is not enough you might be tempted to do something like this:
while (!future.isDone()) {
// do something else
}
value = future.get();
// do something with value
but this potentially blocks the thread ... in effect. You don't get to move past the end of the above code until the future has been completed.
If you don't care when the value is available because you don't intend to do anything with it, you can simply ignore the future.
Finally, the other way to deliver values asynchronously is using callbacks. You could provide a callback function as a parameter to your getOfflinePlayerDataAsync method. Then you could deliver the result like this:
DiscoBox.schedule(() -> callback(handler.loadObject(...))).createAsyncTask();
The callback might simply assigned the returned value to some shared variable, or it could do something more complicated. The key thing is that it will execute on the async task's thread, not on the thread that calls getOfflinePlayerDataAsync.

Related

How can I block ConcurrentHashMap get() operations during a put()

ConcurrentHashMap<String, Config> configStore = new ConcurrentHashMap<>();
...
void updateStore() {
Config newConfig = generateNewConfig();
Config oldConfig = configStore.get(configName);
if (newConfig.replaces(oldConfig)) {
configStore.put(configName, newConfig);
}
}
The ConcurrentHashMap can be read by multiple threads but can be updated only by a single thread. I'd like to block the get() operations when a put() operation is in progress. The rationale here being that if a put() operation is in progress, that implies the current entry in the map is stale and all get() operations should block until the put() is complete. How can I go about achieving this in Java without synchronizing the whole map?
It surely looks like you can defer this to compute and it will take care for that for you:
Config newConfig = generateNewConfig();
configStore.compute(
newConfig,
(oldConfig, value) -> {
if (newConfig.replaces(oldConfig)) {
return key;
}
return oldConfig;
}
);
You get two guarantees from using this method:
Some attempted update operations on this map by other threads may be blocked while computation is in progress, so the computation should be short and simple
and
The entire method invocation is performed atomically
according to its documentation.
The accepted answer proposed to use compute(...) instead of put().
But if you want
to block the get() operations when a put() operation is in progress
then you should also use compute(...) instead of get().
That's because for ConcurrentHashMap get() doesn't block while compute() is in progress.
Here is a unit test to prove it:
#Test
public void myTest() throws Exception {
var map = new ConcurrentHashMap<>(Map.of("key", "v1"));
var insideComputeLatch = new CountDownLatch(1);
var threadGet = new Thread(() -> {
try {
insideComputeLatch.await();
System.out.println("threadGet: before get()");
var v = map.get("key");
System.out.println("threadGet: after get() (v='" + v + "')");
} catch (InterruptedException e) {
throw new Error(e);
}
});
var threadCompute = new Thread(() -> {
System.out.println("threadCompute: before compute()");
map.compute("key", (k, v) -> {
try {
System.out.println("threadCompute: inside compute(): start");
insideComputeLatch.countDown();
threadGet.join();
System.out.println("threadCompute: inside compute(): end");
return "v2";
} catch (InterruptedException e) {
throw new Error(e);
}
});
System.out.println("threadCompute: after compute()");
});
threadGet.start();
threadCompute.start();
threadGet.join();
threadCompute.join();
}
Output:
threadCompute: before compute()
threadCompute: inside compute(): start
threadGet: before get()
threadGet: after get() (v='v1')
threadCompute: inside compute(): end
threadCompute: after compute()
This fundamentally doesn't work. Think about it: When the code realizes that the information is stale, some time passes and then a .put call is done. Even if the .put call somehow blocks, the timeline is as follows:
Some event occurs in the cosmos that makes your config stale.
Some time passes. [A]
Your run some code that realizes that this is the case.
Some time passes. [B]
Your code begins the .put call.
An extremely tiny amount of time passes. [C]
Your code finishes the .put call.
What you're asking for is a strategy that eliminates [C] while doing absolutely nothing whatsoever to prevent reads of stale data at point [A] and [B], both of which seem considerably more problematic.
Whatever, just give me the answer
ConcurrentHashMap is just wrong if you want this, it's a thing that is designed for multiple concurrent (hence the name) accesses. What you want is a plain old HashMap, where every access to it goes through a lock. Or, you can turn the logic around: The only way to do what you want is to engage a lock for everything (both reads and writes); at which point the 'Concurrent' part of ConcurrentHashMap has become completely pointless:
private final Object lock = new Object[0];
public void updateConfig() {
synchronized (lock) {
// do the stuff
}
}
public Config getConfig(String key) {
synchronized (lock) {
return configStore.get(key);
}
}
NB: Use private locks; public locks are like public fields. If there is an object that code outside of your control can get a ref to, and you lock on it, you need to describe the behaviour of your code in regards to that lock, and then sign up to maintain that behaviour forever, or indicate clearly when you change the behaviour that your API just went through a breaking change, and you should thus also bump the major version number.
For the same reason public fields are almost invariably a bad idea in light of the fact that you want API control, you want the refs you lock on to be not accessible to anything except code you have under your direct control. Hence why the above code does not use the synchronized keyword on the method itself (as this is usually a ref that leaks all over the place).
Okay, maybe I want the different answer
The answer is either 'it does not matter' or 'use locks'. If [C] truly is all you care about, that time is so short, and pales in comparison to the times for [A] and [B], that if A/B are acceptable, certainly so is C. In that case: Just accept the situation.
Alternatively, you can use locks but lock even before the data ever becomes stale. This timeline guarantees that no stale data reads can ever occur:
The cosmos cannot ever make your data stale.
Your code, itself, is the only causal agent for stale date.
Whenever code runs that will or may end up making data stale:
Acquire a lock before you even start.
Do the thing that (may) make some config stale.
Keep holding on to the lock; fix the config.
Release the lock.
How can I go about achieving this in Java without synchronizing the whole map?
There are some good answers here but there is a simpler answer to use the ConcurrentMap.replace(key, oldValue, newValue) method which is atomic.
while (true) {
Config newConfig = generateNewConfig();
Config oldConfig = configStore.get(configName);
if (!newConfig.replaces(oldConfig)) {
// nothing to do
break;
}
// this is atomic and will only replace the config if the old hasn't changed
if (configStore.replace(configName, oldConfig, newConfig)) {
// if we replaced it then we are done
break;
}
// otherwise, loop around and create a new config
}

what is the right approach to combine CompletableFuture and JdbcTamplate?

I am trying to make some simple queries to the database using JdbcTemplate. Will my approach be right?
#Async
public CompletableFuture<List<ResultClass1> query1() {
return CompletableFuture.completedFuture(jdbcTemplate.query("my sql",rowMap, paramter));
}
#Async
public CompletableFuture<List<ResultClass2> query2() {
return CompletableFuture.completedFuture(jdbcTemplate.query("my sql2",rowMap, paramter));
}
CompletableFuture<List<ResultClass1> future1 = dao1.query1();
CompletableFuture<List<ResultClass2> future2 = dao2.query2();
CompletableFuture.allOf(future1, future2).join();
I think you've got it, if what you're trying to do is run those queries simultaneously and wait for both to finish. However, your application is blocked until both finish. To avoid this, typically you do something like this:
CompletionStage<CombinedResult> combinedResult =
CompletableFuture.allOf(future1, future2).thenApplyAsync(dummy -> {
List<ResultClass1> query1Results = future1.join();
List<ResultClass2> query2Results = future2.join();
// more code...
return someCombinedResult;
});
This allows you to continue writing code around a hypothetical combined result, all the way up your call stack, so that you can even return to your main process's event loop, which frees your process to do other things until your queries complete.

Running a method using multithread in java

I have method as
public List<SenderResponse> sendAllFiles(String folderName) {
List<File> allFiles = getListOfFiles();
List<SenderResponse> finalResponse = new ArrayList<SenderResponse>();
for (File file : allFiles) {
finalResponse.getResults().add(sendSingleFile(file));
}
return finalResponse;
}
which is running as a single thread. I want run sendSingleFile(file) using multithread so I can reduce the total time taken to send files.
how can I run sendSingleFile(file) using multithreads for various files and get the final response?
I found few articles using threadpoolexecutor. But how to handle the response got during the sendSingleFile(file) and add it to one Final SenderResponse?
I am kind of new to multi-thread. Please suggest the best way to process these files.
Define an executor service
ExecutorService executor = Executors.newFixedThreadPool(MAX_THREAD); //Define integer value of MAX_THREAD
Then for each job you can do something like this:-
Callable<SenderResponse> task = () -> {
try {
return sendSingleFile(file);
}
catch (InterruptedException e) {
throw new IllegalStateException("Interrupted", e);
}
};
Future<SenderResponse> future = executor.submit(task);
future.get(MAX_TIME_TO_WAIT, TimeUnit.SECONDS); //Blocking call. MAX_TIME_TO_WAIT is max time future will wait for the process to execute.
You start by writing code that works works for the single-thread solution. The code you posted wouldn't even compile; as the method signature says to return SenderResponse; whereas you use/return a List<SenderResponse> within the method!
When that stuff works, you continue with this:
You create an instance of
ExecutorService, based on as many threads as you want to
You submit tasks into that service.
Each tasks knows about that result list object. The task does its work, and adds the result to that result list.
The one point to be careful about: making sure that add() is synchronized somehow - having multiple threads update an ordinary ArrayList is not safe.
For your situation, I would use a work stealing pool (ForkJoin executor service) and submit "jobs" to it. If you're using guava, you can wrap that in a listeningDecorator which will allow you to add a listener on the futures it returns.
Example:
// create the executor service
ListeningExecutorService exec = MoreExecutors.listeningDecorator(Executors.newWorkStealingPool());
for(Foo foo : bar) {
// submit can accept Runnable or Callable<T>
final ListenableFuture<T> future = exec.submit(() -> doSomethingWith(foo));
// Run something when it is complete.
future.addListener(() -> doSomeStuff(future), exec);
}
Note that the listener will be called whether the future was successful or not.

How to confirm Future returns value as soon as it has one

Please can someone advise how to use Callable and Future in this scenario
I want to be able to submit mulitple bids for items from different users.
I am starting a new thread and when the winning bid value comes back I wanted to return the value. How do I spawn a new thread and return a value as soon as I have one. Will having Future.get() as the next line wait for the value to return or can it return empty value?
public AuctionBid getWinningBid(String itemCode){
Callable<AuctionBid> winningBidCallable = () -> store.getWinningBid(itemCode);
Future<AuctionBid> future = executorService.submit(winningBidCallable);
return Future.get(); // can this return empty object
}
Future.get() is a blocking call, So It will wait until Future has any value(provided there is no exception).
So in your case, Future.get() can fulfill your requirement.

How to return a result at the moment of an interrupt a.k.a. how to retrieve the result of a Callable although it's cancelled

I've grown desperate all night on this problem and I have not found help during online research, so here we go.
I want to do an optimization process which is meant to be interrupted at a time that is being determined on runtime. Once the interrupt is thrown, I want the best result that has been calculated until that moment to be returned.
My Idea was to put the calculations into a Callable. Because Callables can return results and also - at least I thought - be interrupted. My call() method would be able to return my best result when an interrupt is thrown. But apparently, the only way to force an interrupt into the Callable is to do task.cancel(true); which then throws a CancellationException before result = task.get(); can retrieve the result.
A rough scetch of my code:
SearchCallable myCallable = new myCallable(...);
ExecutorService service = Executors.newFixedThreadPool(1);
Future<int[]> task = service.submit(myCallable);
try {
Thread.sleep(getTimeToCalculate(...));
} catch (InterruptedException e) {[...]}
task.cancel(true);
try {
result = task.get();
} catch(InterruptedException ie){[...]
} catch (ExecutionException ee) {[...]}
myCallable looks somewhat like this:
public class myCallable implements Callable<Object> {
public myCallable(...){
[...]
}
public Object call(){
return anObjectOfAnotherClass.saidCalculations();
}
}
Where an auxiliary method which does a lot of recursion contains this:
if(Thread.interrupted()){
throw new InterruptedException();
}
And said auxiliary method catches this InterruptedException and returns it's best result so far, so myCallable gets this result and actually should return it.
So, how can I get the interrupt in there and still get my result? Or is there some completely different way to implement my original idea?
So, there is one thread performing the computation; this thread is interrupted and the "best result" is what it could come up with.
Then you can, instead of a Callable, use a Runnable and pass a reference to a structure bearing the result when you initialize it.
You can then submit that runnable to your thread pool; when it is "done with its work" (either it is really done, or it was interrupted), you'll just have to read the data in the reference you passed to your Runnable as an argument.
EDIT Since the result of the computation is a( reference to a)n object, I suggest the use of an AtomicReference.

Categories