I have trouble understanding the usage of @Async
annotation and methods since I am quite inexperienced in the multithreading field.
I have some Map<Integer, String> map
and I want to update this map
using the asynchronous method calls. This method makes HTTP GET
request on a page with int id
which returns String string
as result - it is updated to the map
and I need to get the updated result value:
@Async
public Future<Entry<Integer, String>> updateEntry(Integer key, String value) {
Entry<Integer, String> entry = // Method call updates String value (let's say HTTP GET request takes few seconds)
return new AsyncResult<Entry<Integer, String>>(entry);
}
Since this method won't work if called using this
, there is another class executing those methods:
private final Map<Integer, String> map = new ConcurrentHashMap<>();
private void update() {
// KICK THE ASYNC METHODS UP
List<Future<Entry<Integer, String>>> futures = new ArrayList<>();
map.forEach((key, value) -> {
futures.add(asyncObject.updateEntry(value));
});
// FETCH THE RESULTS
Iterator<Future<Entry<Integer, String>>> iterator = futures.iterator();
while (iterator.hasNext()) {
Future<Entry<Integer, String>> future = iterator.next();
if (future.isDone()) {
try {
Entry<Integer, String> entry = future.get();
this.map.put(entry.getKey(), entry.getValue());
iterator.remove();
} catch (InterruptedException | ExecutionException e) {
// SH*T HAPPENS, LOG IT
}
}
if (!iterator.hasNext()) {
iterator = futures.iterator();
}
}
}
I have stored all the future results in futures
and the result sooner or later will appear. I think a good way is to use endless while-loop
to check if Future::isDone
, the iteration above is briefly described below:
- Iterate the
futures
list endlessly (0, 1, 2 .. 8, 9, 10, 0, 1, 2...) using endless Iterator. - If
Future<Entry<Integer, String>>
is done:- Update the map using
Map::put
which replaces the entry - Remove
Future<Entry<Integer, String>>
from theList
- Update the map using
- Stop the endless iteration if the list
futures
is empty.
This solution surprisingly (my first multithreading experiment) works.
Is this solution thread safe and of a correct approach? Is the usage of ConcurrentHashMap
sufficient? I have no idea how to test unless printing the actions to the console or log. What might happen if the map
would be updated by another @Async
call at the moment of update
method call - would be making this method synchronized
sufficent?