Reputation: 17077
In AJAX, suppose i submit a request asynchronously. When the reposne returns , it executes a callback function.
What is the best way to implement the same in a java multithreaded environment? i.e Main thread creates a child thread and submits a task and then the child thread returns a callback function needs to be executed by the main thread.
Is this possible? In main thread I can do wait() and in child thread i can do notify() but in that case the main thread will wait until the child thread finishes. But in AJAX the main thread continues its operation...that is what i want
Upvotes: 1
Views: 2800
Reputation: 37822
You could use an ExecutorService
to do tasks on the background and then use the methods of the Future
you get back to wait for the result. For example:
class Main {
private static final ExecutorService es = Executors.newCachedThreadPool();
public static void main(final String... args) throws Throwable {
List<Future<Integer>> results = new ArrayList<>();
for (int i = 0; i < 10; i++) {
results.add(asyncSum(i, i*i));
}
// here, in the main thread, you can do whatever you want
// while the calculations are performed in background threads
// ...
// after the main thread finishes what it was doing, it
// can process the futures
for (final Future<Integer> result : results) {
System.out.println(result.get());
}
}
// this method launches a calculation on a worker thread and immediately
// returns a Future, which is a reference to the result of the calculation
// once it is completed
private static Future<Integer> asyncSum(final int a, final int b) {
return es.submit(new Callable<Integer>() {
@Override public Integer call() throws Exception {
return a + b;
}
});
}
}
In the example above, the main thread will block until the first computation is done, then print it. Then block until the second computation is done, then print it, etc.
If you wish to print the results as they become available (in an unspecified order), then you could use a CompletionService
, and instead of having a list of results and iterating on it, you'd get your futures from the CompletionService itself through its .take()
method, that blocks until a computation is finished, or .poll()
, which returns a Future if there there are finished computations, or null if there are no computations finished -- this way your main thread will never block.
The following example uses a CompletionService
. It shows a main thread that never blocks, uses background threads to do calculations and process the results as they become available:
class Main {
public static void main(String[] args) throws Throwable {
final ExecutorService es = Executors.newCachedThreadPool();
final CompletionService<Integer> cs = new ExecutorCompletionService<>(es);
submitSomeCalculations(cs);
while (true) {
doMainThreadWork();
processFinishedCalculations(cs);
}
}
private static void submitSomeCalculations(final CompletionService<Integer> cs) {
for (int i = 0; i < 10; i++) {
submitAsyncSum(cs, i, i * i);
}
}
private static void submitAsyncSum(final CompletionService<Integer> cs, final int a, final int b) {
cs.submit(new Callable<Integer>() {
@Override public Integer call() throws Exception {
Thread.sleep(100 + (long) (Math.random() * 900));
return a + b;
}
});
}
private static void processFinishedCalculations(final CompletionService<Integer> cs) throws ExecutionException, InterruptedException {
while (true) {
final Future<Integer> result = cs.poll();
if (result == null) {
System.out.println("> no finished results...");
break;
} else {
System.out.println("> result available: " + result.get());
}
}
}
static void doMainThreadWork() {
System.out.println("work from main thread...");
}
}
Upvotes: 3