Ah, amazing question. What you want is a callback - a method that needs to be pushed to a thread's call stack when some previous task is done. A crude way to do this is to define a new task (using a Runnable or a Callable) after your task:
Thread T = new Thread() {
public void run() {
//after this code finished
Runnable callback = () -> {//some task};
ES.submit(callback); //ES = ExecutorService
}
};
Now supposing you want to execute a task when the second task is complete. You would do something like:
Thread T = new Thread() {
public void run() {
//after this code finished
Runnable callback = () -> {
//task completed
//second callback
Runnable callback2 = () -> {};
ES.submit(callback2);
};
}
};
You see the code is getting hideous and non-idiomatic (the notorious 'Callback Hell'). To counter this, Java 8 introduced the CompleteableFuture<T>
class. You can basically get a CompleteableFuture<T>
as a promise and then apply methods like:
promise.thenApplyAsync(callback).thenApplyAsync(callback)...
CompletableFutures<T>
are literally Javascript
promises - they can be either in pending stage, or complete, or complete with an error.
Reactive streams are the next step. But of course, to understand it, you need to understand the above things properly.