use FutureTask for concurrency - java

I have a service like:
class DemoService {
Result process(Input in) {
filter1(in);
if (filter2(in)) return...
filter3(in);
filter4(in);
filter5(in);
return ...
}
}
Now I want it faster and I found that some filters can start at the same time, while some filters must wait for others to finish. For example:
filter1--
|---filter3--
filter2-- |---filter5
---filter4--
which means:
1.filter1 and filter2 can start at the same time, so do filter3 and filter4
2.filter3 and filter4 must wait for filter2 to finish
one more thing:
if filter2 returns true, then the 'process' method returns immediately and ignores the following filters.
now my solution is using FutureTask:
// do filter's work at FutureTask
for (Filter filter : filters) {
FutureTask<RiskResult> futureTask = new FutureTask<RiskResult>(new CallableFilter(filter, context));
executorService.execute(futureTask);
}
//when all FutureTask are submitted, wait for result
for(Filter filter : filters) {
if (filter.isReturnNeeded()) {
FutureTask<RiskResult> futureTask = context.getTask(filter.getId());
riskResult = futureTask.get();
if (canReturn(filter, riskResult)) {
returnOk = true;
return riskResult;
}
}
}
my CallableFilter:
public class CallableFilter implements Callable<RiskResult> {
private Filter filter;
private Context context;
#Override
public RiskResult call() throws Exception {
List<Filter> dependencies = filter.getDependentFilters();
if (dependencies != null && dependencies.size() > 0) {
//wait for its dependency filters to finish
for (Filter d : dependencies) {
FutureTask<RiskResult> futureTask = context.getTask(d.getId());
futureTask.get();
}
}
//do its own work
return filter.execute(context);
}
}
I want to know:
1.is it a good idea to use FutureTask in the case? is there a better solution?
2.the overhead of thread context switch.
thanks!

In Java 8 you can use CompletableFuture to chain your filters after each other. Use the thenApply and thenCompose family of methods in order to add new asynchronous filters to the CompletableFuture - they will execute after the previous step is finished. thenCombine combines two independent CompletableFutures when both are finished. Use allOf to wait for the result of more than two CompletableFuture objects.
If you can't use Java 8, then the Guava ListenableFuture can do the same, see Listenable Future Explained. With Guava you can wait for multiple independently running filters to finish with Futures.allAsList - this also returns a ListenableFuture.
With both approaches the idea is that after you declare your future actions, their dependencies on each other, and their threads, you get back a single Future object, which encapsulates your end result.
EDIT: The early return could be implemented by explicitly completing the CompletableFuture with the complete() method or using a Guava SettableFuture (which implements ListenableFuture)

You can use a ForkJoinPool for parallelization, which is explicitely thought for that kind of parallel computions:
(...) Method join() and its variants are appropriate for use only when completion dependencies are acyclic; that is, the parallel computation can be described as a directed acyclic graph (DAG) (...)
(see ForkJoinTask)
The advantage of a ForkJoinPool is that every task can spawn new tasks and also wait for them to complete without actually blocking the executing thread (which otherwise might cause a deadlock if more tasks are waiting for others to complete than threads are available).
This is an example that should work so far, although it has some limitations yet:
It ignores filter results
It does not prematurely finish execution if filter 2 returns true
Exception handling is not implemented
The main idea behind this code: Every filter is represented as Node that may depend on other nodes (= filters that must complete before this filter can execute). Dependent nodes are spawned as parallel tasks.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
public class Node<V> extends RecursiveTask<V> {
private static final short VISITED = 1;
private final Callable<V> callable;
private final Set<Node<V>> dependencies = new HashSet<>();
#SafeVarargs
public Node(Callable<V> callable, Node<V>... dependencies) {
this.callable = callable;
this.dependencies.addAll(Arrays.asList(dependencies));
}
public Set<Node<V>> getDependencies() {
return this.dependencies;
}
#Override
protected V compute() {
try {
// resolve dependencies first
for (Node<V> node : dependencies) {
if (node.tryMarkVisited()) {
node.fork(); // start node
}
}
// wait for ALL nodes to complete
for (Node<V> node : dependencies) {
node.join();
}
return callable.call();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
public boolean tryMarkVisited() {
return compareAndSetForkJoinTaskTag((short) 0, VISITED);
}
}
Usage example:
public static void main(String[] args) {
Node<Void> filter1 = new Node<>(filter("filter1"));
Node<Void> filter2 = new Node<>(filter("filter2"));
Node<Void> filter3 = new Node<>(filter("filter3"), filter1, filter2);
Node<Void> filter4 = new Node<>(filter("filter4"), filter1, filter2);
Node<Void> filter5 = new Node<>(filter("filter5"), filter3, filter4);
Node<Void> root = new Node<>(() -> null, filter5);
ForkJoinPool.commonPool().invoke(root);
}
public static Callable<Void> filter(String name) {
return () -> {
System.out.println(Thread.currentThread().getName() + ": start " + name);
Thread.sleep(1000);
System.out.println(Thread.currentThread().getName() + ": end " + name);
return null;
};
}

Related

How to make a future that gets completed when any of the given CompletableFutures is completed with a result that matches a certain predicate?

I have a list of CompletableFuture<MyService>:
List<CompletableFuture<MyService>>
where MyService is immutable like the following:
public class MyService {
public boolean isAvailable() {
return true; // or false
}
}
I now want a future that is completed when one of the futures:
is completed; and
for the MyService instance as provided by that future: MyService.isAvailable() returns true
When proceeding, I need to have the MyService instance that is available. In other words, I want a CompletableFuture<MyService> which completes when the two conditions are met.
How can I do this? I know I can use CompletableFuture.anyOf(...) to proceeed when one of the futures completes, but I am unsure how to integrate the second requirement: MyService.isAvailable() must be true.
Update: I think I understood your problem now. Would it help you to proxy your futures like this?
List<CompletableFuture<MyService>> givenFutures; // wherever they came from
CompletableFuture<MyService>[] myFutures = givenFutures.stream()
.map(future -> {
final CompletableFuture<MyService> futureWithCheck = new CompletableFuture<>();
future.thenAccept(myService -> {
if (myService.isAvailable()) {
futureWithCheck.complete(myService);
}
});
return futureWithCheck;})
.toArray(CompletableFuture[]::new);
// blocking
MyService availableService = (MyService) CompletableFuture.anyOf(myFutures).get();
// do what you want to do with the available service
Update 2: I thought about your question regarding thenCompose and perhaps the middle part of my solution could be expressed like this:
CompletableFuture<MyService>[] myFutures = givenFutures.stream()
.map(future ->
future.thenCompose(myService ->
myService.isAvailable() ? CompletableFuture.completedFuture(myService) : new CompletableFuture<>()))
.toArray(CompletableFuture[]::new);
Old Answer, for completeness:
(was gonna comment but I have too little reputation)
Looks like you will either have to poll MyService.isAvailable() repeatedly and complete another CompletableFuture once this returns true or MyService will (like Didier L commented) have to return a Future which it keeps track of and completes, once the internal members you mentioned are changed. So for example the setter for each member involved will have to check whether isAvailable() is true and if so, complete all futures that it handed out before.
In both cases you have to chain the additional Future with the ones you have. Guavas Futures has useful methods, but probably CompletableFuture.allOf(…) will do the job.
You can try something like the following service, where the future gets completed only if the service is available:
public static class MyService {
private String name;
public MyService(String name) {
this.name = name;
}
public String toString() {
return name;
}
public CompletableFuture<MyService> isAvailable() {
CompletableFuture<MyService> future = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
boolean available = checkAvailability();
if (available)
future.complete(this);
});
return future;
}
private boolean checkAvailability() {
try {
int ms = new Random().nextInt(1000);
Thread.sleep(ms);
} catch (InterruptedException e) {
}
return new Random().nextBoolean();
}
}
And then use the service like this:
MyService s1 = new MyService("one");
MyService s2 = new MyService("two");
CompletableFuture<MyService> f1 = s1.isAvailable();
CompletableFuture<MyService> f2 = s2.isAvailable();
System.out.println("waiting for the first service to be available...");
CompletableFuture<Object> any = CompletableFuture.anyOf(f1, f2);
System.out.println("and the winner is: " + any.get());
// you can now safely cancel all futures
f1.cancel(true);
f2.cancel(true);
Considering that a CompletableFuture can only be completed once, you can create one that will be completed by the first future that returns an available service:
List<CompletableFuture<MyService>> myServiceFutures = …
final CompletableFuture<MyService> availableMyServiceFuture = new CompletableFuture<>();
myServiceFutures.forEach(future -> future.thenAccept(myService -> {
if (myService.isAvailable()) {
// call will be ignored if already completed
availableMyServiceFuture.complete(myService);
}
}));
Additionally, you may want this future to complete exceptionally if no service is available:
CompletableFuture.allOf(myServiceFutures.toArray(new CompletableFuture[myServiceFutures.size()]))
.whenComplete((e, r) -> {
// TODO handle failure of individual futures if that can happen
if (myServiceFutures.stream().map(CompletableFuture::join).noneMatch(MyService::isAvailable)) {
availableMyServiceFuture.completeExceptionally(new IllegalStateException("No service is available"));
}
});

How to wait for completion of multiple tasks in Java?

What is the proper way to implement concurrency in Java applications? I know about Threads and stuff, of course, I have been programming for Java for 10 years now, but haven't had too much experience with concurrency.
For example, I have to asynchronously load a few resources, and only after all have been loaded, can I proceed and do more work. Needless to say, there is no order how they will finish. How do I do this?
In JavaScript, I like using the jQuery.deferred infrastructure, to say
$.when(deferred1,deferred2,deferred3...)
.done(
function(){//here everything is done
...
});
But what do I do in Java?
You can achieve it in multiple ways.
1.ExecutorService invokeAll() API
Executes the given tasks, returning a list of Futures holding their status and results when all complete.
2.CountDownLatch
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon -- the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.
3.ForkJoinPool or newWorkStealingPool() in Executors is other way
Have a look at related SE questions:
How to wait for a thread that spawns it's own thread?
Executors: How to synchronously wait until all tasks have finished if tasks are created recursively?
I would use parallel stream.
Stream.of(runnable1, runnable2, runnable3).parallel().forEach(r -> r.run());
// do something after all these are done.
If you need this to be asynchronous, then you might use a pool or Thread.
I have to asynchronously load a few resources,
You could collect these resources like this.
List<String> urls = ....
Map<String, String> map = urls.parallelStream()
.collect(Collectors.toMap(u -> u, u -> download(u)));
This will give you a mapping of all the resources once they have been downloaded concurrently. The concurrency will be the number of CPUs you have by default.
If I'm not using parallel Streams or Spring MVC's TaskExecutor, I usually use CountDownLatch. Instantiate with # of tasks, reduce once for each thread that completes its task. CountDownLatch.await() waits until the latch is at 0. Really useful.
Read more here: JavaDocs
Personally, I would do something like this if I am using Java 8 or later.
// Retrieving instagram followers
CompletableFuture<Integer> instagramFollowers = CompletableFuture.supplyAsync(() -> {
// getInstaFollowers(userId);
return 0; // default value
});
// Retrieving twitter followers
CompletableFuture<Integer> twitterFollowers = CompletableFuture.supplyAsync(() -> {
// getTwFollowers(userId);
return 0; // default value
});
System.out.println("Calculating Total Followers...");
CompletableFuture<Integer> totalFollowers = instagramFollowers
.thenCombine(twitterFollowers, (instaFollowers, twFollowers) -> {
return instaFollowers + twFollowers; // can be replaced with method reference
});
System.out.println("Total followers: " + totalFollowers.get()); // blocks until both the above tasks are complete
I used supplyAsync() as I am returning some value (no. of followers in this case) from the tasks otherwise I could have used runAsync(). Both of these run the task in a separate thread.
Finally, I used thenCombine() to join both the CompletableFuture. You could also use thenCompose() to join two CompletableFuture if one depends on the other. But in this case, as both the tasks can be executed in parallel, I used thenCombine().
The methods getInstaFollowers(userId) and getTwFollowers(userId) are simple HTTP calls or something.
You can use a ThreadPool and Executors to do this.
https://docs.oracle.com/javase/tutorial/essential/concurrency/pools.html
This is an example I use Threads. Its a static executerService with a fixed size of 50 threads.
public class ThreadPoolExecutor {
private static final ExecutorService executorService = Executors.newFixedThreadPool(50,
new ThreadFactoryBuilder().setNameFormat("thread-%d").build());
private static ThreadPoolExecutor instance = new ThreadPoolExecutor();
public static ThreadPoolExecutor getInstance() {
return instance;
}
public <T> Future<? extends T> queueJob(Callable<? extends T> task) {
return executorService.submit(task);
}
public void shutdown() {
executorService.shutdown();
}
}
The business logic for the executer is used like this: (You can use Callable or Runnable. Callable can return something, Runnable not)
public class MultipleExecutor implements Callable<ReturnType> {//your code}
And the call of the executer:
ThreadPoolExecutor threadPoolExecutor = ThreadPoolExecutor.getInstance();
List<Future<? extends ReturnType>> results = new LinkedList<>();
for (Type Type : typeList) {
Future<? extends ReturnType> future = threadPoolExecutor.queueJob(
new MultipleExecutor(needed parameters));
results.add(future);
}
for (Future<? extends ReturnType> result : results) {
try {
if (result.get() != null) {
result.get(); // here you get the return of one thread
}
} catch (InterruptedException | ExecutionException e) {
logger.error(e, e);
}
}
The same behaviour as with $.Deferred in jQuery you can archive in Java 8 with a class called CompletableFuture. This class provides the API for working with Promises. In order to create async code you can use one of it's static creational methods like #runAsync, #supplyAsync. Then applying some computation of results with #thenApply.
I usually opt for an async notify-start, notify-progress, notify-end approach:
class Task extends Thread {
private ThreadLauncher parent;
public Task(ThreadLauncher parent) {
super();
this.parent = parent;
}
public void run() {
doStuff();
parent.notifyEnd(this);
}
public /*abstract*/ void doStuff() {
// ...
}
}
class ThreadLauncher {
public void stuff() {
for (int i=0; i<10; i++)
new Task(this).start();
}
public void notifyEnd(Task who) {
// ...
}
}

Java happens-before consistent thread view on two ConcurrentMaps

I have a java class to handle a multithreaded subscription service. By implementing the Subscribable interface, tasks can be submitted to the service and periodically executed. A sketch of the code is seen below:
import java.util.concurrent.*;
public class Subscribtions {
private ConcurrentMap<Subscribable, Future<?>> futures = new ConcurrentHashMap<Subscribable, Future<?>>();
private ConcurrentMap<Subscribable, Integer> cacheFutures = new ConcurrentHashMap<Subscribable, Integer>();
private ScheduledExecutorService threads;
public Subscribtions() {
threads = Executors.newScheduledThreadPool(16);
}
public void subscribe(Subscribable subscription) {
Runnable runnable = getThread(subscription);
Future<?> future = threads.scheduleAtFixedRate(runnable, subscription.getInitialDelay(), subscription.getPeriod(), TimeUnit.SECONDS);
futures.put(subscription, future);
}
/*
* Only called from controller thread
*/
public void unsubscribe(Subscribable subscription) {
Future<?> future = futures.remove(subscription); //1. Might be removed by worker thread
if (future != null)
future.cancel(false);
else {
//3. Worker-thread view := cacheFutures.put() -> futures.remove()
//4. Controller-thread has seen futures.remove(), but has it seen cacheFutures.put()?
}
}
/*
* Only called from worker threads
*/
private void delay(Runnable runnable, Subscribable subscription, long delay) {
cacheFutures.put(subscription, 0); //2. Which is why it is cached first
Future<?> currentFuture = futures.remove(subscription);
if (currentFuture != null) {
currentFuture.cancel(false);
Future<?> future = threads.scheduleAtFixedRate(runnable, delay, subscription.getPeriod(), TimeUnit.SECONDS);
futures.put(subscription, future);
}
}
private Runnable getThread(Subscribable subscription) {
return new Runnable() {
public void run() {
//Do work...
boolean someCondition = true;
long someDelay = 100;
if (someCondition) {
delay(this, subscription, someDelay);
}
}
};
}
public interface Subscribable {
long getInitialDelay();
long getPeriod();
}
}
So the class permits to:
Subscribe to new tasks
Unsubscribe from existing tasks
Delay a periodically executed task
Subscriptions are added/removed by an external controlling thread, but delays are incurred only by the internal worker threads. This could happen, if for instance a worker thread found no update from the last execution or e.g. if the thread only needs to execute from 00.00 - 23.00.
My problem is that a worker thread may call delay() and remove its future from the ConcurrentMap, and the controller thread may concurrently call unsubscribe(). Then if the controller thread checks the ConcurrentMap before the worker thread has put in a new future, the unsubscribe() call will be lost.
There are some (not exhaustive list perhaps) solutions:
Use a lock between the delay() and unsubscribe() methods
Same as above, but one lock per subscribtion
(preferred?) Use no locks, but "cache" removed futures in the delay() method
As for the third solution, since the worker-thread has established the happens-before relationship cacheFutures.put() -> futures.remove(), and the atomicity of ConcurrentMap makes the controller thread see futures.remove(), does it also see the same happens-before relationship as the worker thread? I.e. cacheFutures.put() -> futures.remove()? Or does the atomicity only hold for the futures map with updates to other variables being propagated later?
Any other comments are also welcome, esp. considering use of the volatile keyword. Should the cache-map be declared volatile? thanks!
One lock per subscription would require you to maintain yet another map, and possibly thereby to introduce additional concurrency issues. I think that would be better avoided. The same applies even more so to caching removed subscriptions, plus that affords the added risk of unwanted resource retention (and note that it's not the Futures themselves that you would need to cache, but rather the Subscribables with which they are associated).
Any way around, you will need some kind of synchronization / locking. For example, in your option (3) you need to avoid an unsubscribe() for a given subscription happening between delay() caching that subscription and removing its Future. The only way you could avoid that without some form of locking would be if you could use just one Future per subscription, kept continuously in place from the time it is enrolled by subscribe() until it is removed by unsubscribe(). Doing so is not consistent with the ability to delay an already-scheduled subscription.
As for the third solution, since the worker-thread has established the happens-before relationship cacheFutures.put() -> futures.remove(), and the atomicity of ConcurrentMap makes the controller thread see futures.remove(), does it also see the same happens-before relationship as the worker thread?
Happens-before is a relationship between actions in an execution of a program. It is not specific to any one thread's view of the execution.
Or does the atomicity only hold for the futures map with updates to other variables being propagated later?
The controller thread will always see the cacheFutures.put() performed by an invocation of delay() occuring before the futures.remove() performed by that same invocation. I don't think that helps you, though.
Should the cache-map be declared volatile?
No. That would avail nothing, because although the contents of that map change, the map itself is always the same object, and the reference to it does not change.
You could consider having subscribe(), delay(), and unsubscribe() each synchronize on the Subscribable presented. That's not what I understood you to mean about having a lock per subscription, but it is similar. It would avoid the need for a separate data structure to maintain such locks. I guess you could also build locking methods into the Subscribable interface if you want to avoid explicit synchronization.
You have a ConcurrentMap but you aren't using it. Consider something along these lines:
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
final class SO33555545
{
public static void main(String... argv)
throws InterruptedException
{
ScheduledExecutorService workers = Executors.newScheduledThreadPool(16);
Subscriptions sub = new Subscriptions(workers);
sub.subscribe(() -> System.out.println("Message received: A"));
sub.subscribe(() -> System.out.println("Message received: B"));
Thread.sleep(TimeUnit.SECONDS.toMillis(30));
workers.shutdown();
}
}
final class Subscriptions
{
private final ConcurrentMap<Subscribable, Task> tasks = new ConcurrentHashMap<>();
private final ScheduledExecutorService workers;
public Subscriptions(ScheduledExecutorService workers)
{
this.workers = workers;
}
void subscribe(Subscribable sub)
{
Task task = new Task(sub);
Task current = tasks.putIfAbsent(sub, task);
if (current != null)
throw new IllegalStateException("Already subscribed");
task.activate();
}
private Future<?> schedule(Subscribable sub)
{
Runnable task = () -> {
sub.invoke();
if (Math.random() < 0.25) {
System.out.println("Delaying...");
delay(sub, 5);
}
};
return workers.scheduleAtFixedRate(task, sub.getPeriod(), sub.getPeriod(), TimeUnit.SECONDS);
}
void unsubscribe(Subscribable sub)
{
Task task = tasks.remove(sub);
if (task != null)
task.cancel();
}
private void delay(Subscribable sub, long delay)
{
Task task = new Task(sub);
Task obsolete = tasks.replace(sub, task);
if (obsolete != null) {
obsolete.cancel();
task.activate();
}
}
private final class Task
{
private final FutureTask<Future<?>> future;
Task(Subscribable sub)
{
this.future = new FutureTask<>(() -> schedule(sub));
}
void activate()
{
future.run();
}
void cancel()
{
boolean interrupted = false;
while (true) {
try {
future.get().cancel(false);
break;
}
catch (ExecutionException ignore) {
ignore.printStackTrace(); /* Cancellation is unnecessary. */
break;
}
catch (InterruptedException ex) {
interrupted = true; /* Keep waiting... */
}
}
if (interrupted)
Thread.currentThread().interrupt(); /* Reset interrupt state. */
}
}
}
#FunctionalInterface
interface Subscribable
{
default long getPeriod()
{
return 4;
}
void invoke();
}

How do I unit test asynchronous methods nicely?

I'm currently unit testing my asynchronous methods using thread locking, usually I inject a CountDownLatch into my asynchronous component and let the main thread wait for it to reach 0. However, this approach just looks plain ugly, and it doesn't scale well, consider what happens when I write 100+ tests for a component and they all sequentially have to wait for a worker thread to do some fake asynchronous job.
So is there another approach? Consider the following example for a simple search mechanism:
Searcher.java
public class Searcher {
private SearcherListener listener;
public void search(String input) {
// Dispatch request to queue and notify listener when finished
}
}
SearcherListener.java
public interface SearcherListener {
public void searchFinished(String[] results);
}
How would you unit test the search method without using multiple threads and blocking one to wait for another? I've drawn inspiration from How to use Junit to test asynchronous processes but the top answer provides no concrete solution to how this would work.
Another approach:
Just dont start the thread. thats all.
Asume you have a SearcherService which uses your Searcher class.
Then don't start the async SearcherService, instead just call searcher.search(), which blocks until search is finished.
Searcher s = new Searcher();
s.search(); // blocks and returns when finished
// now somehow check the result
Writing unit test for async never looks nice.
It's necessary that the testMyAsyncMethod() (main thread) blocks until you are ready to check the correct behaviour. This is necessary because the test case terminates at the end of the method. So there is no way around, the question is only how you block.
A straightforward approach that does not influence much the productive code is to
use a while loop: asume AsyncManager is the class under test:
ArrayList resultTarget = new ArrayList();
AsyncManager fixture = new AsyncManager(resultTarget);
fixture.startWork();
// now wait for result, and avoid endless waiting
int numIter = 10;
// correct testcase expects two events in resultTarget
int expected = 2;
while (numIter > 0 && resulTarget.size() < expected) {
Thread.sleep(100);
numIter--;
}
assertEquals(expected, resulTarget.size());
productive code would use apropriate target in the constructor of AsyncManager or uses another constructor. For test purpose we can pass our test target.
You will write this only for inherent async tasks like your own message queue.
for other code, only unitest the core part of the class that performs the calculation task, (a special algorithm, etc) you dont need to let it run in a thread.
However for your search listener the shown principle with loop and wait is appropriate.
public class SearchTest extends UnitTest implements SearchListener {
public void searchFinished() {
this.isSearchFinished = true;
}
public void testSearch1() {
// Todo setup your search listener, and register this class to receive
Searcher searcher = new Searcher();
searcher.setListener(this);
// Todo setup thread
searcherThread.search();
asserTrue(checkSearchResult("myExpectedResult1"));
}
private boolean checkSearchResult(String expected) {
boolean isOk = false;
int numIter = 10;
while (numIter > 0 && !this.isSearchFinished) {
Thread.sleep(100);
numIter--;
}
// todo somehow check that search was correct
isOk = .....
return isOk;
}
}
Create a synchronous version of the class that listens for its own results and uses an internal latch that search() waits on and searchFinished() clears. Like this:
public static class SynchronousSearcher implements SearcherListener {
private CountDownLatch latch = new CountDownLatch(1);
private String[] results;
private class WaitingSearcher extends Searcher {
#Override
public void search(String input) {
super.search(input);
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
public String[] search(String input) {
WaitingSearcher searcher = new WaitingSearcher();
searcher.listener = this;
searcher.search(input);
return results;
}
#Override
public void searchFinished(String[] results) {
this.results = results;
latch.countDown();
}
}
Then to use it, simply:
String[] results = new SynchronousSearcher().search("foo");
There are no threads, no wait loops and the method returns in the minimal possible time. It also doesn't matter if the search returns instantly - before the call to await() - because await() will immediately return if the latch is already at zero.

Return values from Java Threads

I have a Java Thread like the following:
public class MyThread extends Thread {
MyService service;
String id;
public MyThread(String id) {
this.id = node;
}
public void run() {
User user = service.getUser(id)
}
}
I have about 300 ids, and every couple of seconds - I fire up threads to make a call for each of the id. Eg.
for(String id: ids) {
MyThread thread = new MyThread(id);
thread.start();
}
Now, I would like to collect the results from each threads, and do a batch insert to the database, instead of making 300 database inserts every 2 seconds.
Any idea how I can accomplish this?
The canonical approach is to use a Callable and an ExecutorService. submitting a Callable to an ExecutorService returns a (typesafe) Future from which you can get the result.
class TaskAsCallable implements Callable<Result> {
#Override
public Result call() {
return a new Result() // this is where the work is done.
}
}
ExecutorService executor = Executors.newFixedThreadPool(300);
Future<Result> task = executor.submit(new TaskAsCallable());
Result result = task.get(); // this blocks until result is ready
In your case, you probably want to use invokeAll which returns a List of Futures, or create that list yourself as you add tasks to the executor. To collect results, simply call get on each one.
If you want to collect all of the results before doing the database update, you can use the invokeAll method. This takes care of the bookkeeping that would be required if you submit tasks one at a time, like daveb suggests.
private static final ExecutorService workers = Executors.newCachedThreadPool();
...
Collection<Callable<User>> tasks = new ArrayList<Callable<User>>();
for (final String id : ids) {
tasks.add(new Callable<User>()
{
public User call()
throws Exception
{
return svc.getUser(id);
}
});
}
/* invokeAll blocks until all service requests complete,
* or a max of 10 seconds. */
List<Future<User>> results = workers.invokeAll(tasks, 10, TimeUnit.SECONDS);
for (Future<User> f : results) {
User user = f.get();
/* Add user to batch update. */
...
}
/* Commit batch. */
...
Store your result in your object. When it completes, have it drop itself into a synchronized collection (a synchronized queue comes to mind).
When you wish to collect your results to submit, grab everything from the queue and read your results from the objects. You might even have each object know how to "post" it's own results to the database, this way different classes can be submitted and all handled with the exact same tiny, elegant loop.
There are lots of tools in the JDK to help with this, but it is really easy once you start thinking of your thread as a true object and not just a bunch of crap around a "run" method. Once you start thinking of objects this way programming becomes much simpler and more satisfying.
In Java8 there is better way for doing this using CompletableFuture. Say we have class that get's id from the database, for simplicity we can just return a number as below,
static class GenerateNumber implements Supplier<Integer>{
private final int number;
GenerateNumber(int number){
this.number = number;
}
#Override
public Integer get() {
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
e.printStackTrace();
}
return this.number;
}
}
Now we can add the result to a concurrent collection once the results of every future is ready.
Collection<Integer> results = new ConcurrentLinkedQueue<>();
int tasks = 10;
CompletableFuture<?>[] allFutures = new CompletableFuture[tasks];
for (int i = 0; i < tasks; i++) {
int temp = i;
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(()-> new GenerateNumber(temp).get(), executor);
allFutures[i] = future.thenAccept(results::add);
}
Now we can add a callback when all the futures are ready,
CompletableFuture.allOf(allFutures).thenAccept(c->{
System.out.println(results); // do something with result
});
You need to store the result in a something like singleton. This has to be properly synchronized.
This not the best advice as it is not good idea to handle raw Threads.
You could create a queue or list which you pass to the threads you create, the threads add their result to the list which gets emptied by a consumer which performs the batch insert.
The simplest approach is to pass an object to each thread (one object per thread) that will contain the result later. The main thread should keep a reference to each result object. When all threads are joined, you can use the results.
public class TopClass {
List<User> users = new ArrayList<User>();
void addUser(User user) {
synchronized(users) {
users.add(user);
}
}
void store() throws SQLException {
//storing code goes here
}
class MyThread extends Thread {
MyService service;
String id;
public MyThread(String id) {
this.id = node;
}
public void run() {
User user = service.getUser(id)
addUser(user);
}
}
}
You could make a class which extends Observable. Then your thread can call a method in the Observable class which would notify any classes that registered in that observer by calling Observable.notifyObservers(Object).
The observing class would implement Observer, and register itself with the Observable. You would then implement an update(Observable, Object) method that gets called when Observerable.notifyObservers(Object) is called.

Categories