Thread Communication in Java: join, wait/notify, CountDownLatch, CyclicBarrier, Callable and FutureTask
This article explains how to achieve thread communication and coordination in Java using Thread.join(), Object.wait()/notify(), CountDownLatch, CyclicBarrier, and the Callable/FutureTask pair, providing complete code examples and execution results for each technique.
In Java, thread communication can be achieved using various mechanisms such as Thread.join(), Object.wait() / Object.notify(), CountDownLatch, CyclicBarrier, and the Callable / FutureTask pair.
Sequential execution of two threads – By calling Thread.join() on the first thread, the second thread waits until the first finishes. Example code:
private static void demo1(){
Thread A = new Thread(new Runnable(){
@Override public void run(){ printNumber("A"); }
});
Thread B = new Thread(new Runnable(){
@Override public void run(){ printNumber("B"); }
});
A.start();
B.start();
}
private static void printNumber(String threadName){
int i = 0;
while(i++ < 3){
try{ Thread.sleep(100); }catch(InterruptedException e){ e.printStackTrace(); }
System.out.println(threadName + "print:" + i);
}
}Running the above prints interleaved output because the threads run concurrently.
To make B start only after A finishes, join() is used:
private static void demo2(){
Thread A = new Thread(new Runnable(){
@Override public void run(){ printNumber("A"); }
});
Thread B = new Thread(new Runnable(){
@Override public void run(){
System.out.println("B 开始等待 A");
try{ A.join(); }catch(InterruptedException e){ e.printStackTrace(); }
printNumber("B");
}
});
B.start();
A.start();
}The output shows that B waits until A completes.
Ordered interleaving of two threads – When finer‑grained ordering is required, wait() and notify() on a shared lock object can be used:
/** A 1, B 1, B 2, B 3, A 2, A 3 */
private static void demo3(){
Object lock = new Object();
Thread A = new Thread(new Runnable(){
@Override public void run(){
synchronized(lock){
System.out.println("A 1");
try{ lock.wait(); }catch(InterruptedException e){ e.printStackTrace(); }
System.out.println("A 2");
System.out.println("A 3");
}
}
});
Thread B = new Thread(new Runnable(){
@Override public void run(){
synchronized(lock){
System.out.println("B 1");
System.out.println("B 2");
System.out.println("B 3");
lock.notify();
}
}
});
A.start();
B.start();
}The result is the desired sequence: A prints 1, then B prints 1‑3, then A prints 2‑3.
Using CountDownLatch for "wait for multiple threads" – When several worker threads must finish before a dependent thread proceeds, a CountDownLatch can be used. Example:
private static void runDAfterABC(){
int worker = 3;
CountDownLatch countDownLatch = new CountDownLatch(worker);
new Thread(() -> {
System.out.println("D is waiting for other three threads");
try{ countDownLatch.await();
System.out.println("All done, D starts working");
}catch(InterruptedException e){ e.printStackTrace(); }
}).start();
for(char threadName='A'; threadName<='C'; threadName++){
final String tN = String.valueOf(threadName);
new Thread(() -> {
System.out.println(tN + "is working");
try{ Thread.sleep(100); }catch(Exception e){ e.printStackTrace(); }
System.out.println(tN + "finished");
countDownLatch.countDown();
}).start();
}
}The latch ensures that thread D starts only after A, B and C have called countDown().
Using CyclicBarrier for simultaneous start after preparation – When a group of threads must wait for each other before proceeding, CyclicBarrier is appropriate:
private static void runABCWhenAllReady(){
int runner = 3;
CyclicBarrier cyclicBarrier = new CyclicBarrier(runner);
Random random = new Random();
for(char runnerName='A'; runnerName<='C'; runnerName++){
final String rN = String.valueOf(runnerName);
new Thread(() -> {
long prepareTime = random.nextInt(10000) + 100;
System.out.println(rN + "is preparing for time:" + prepareTime);
try{ Thread.sleep(prepareTime); }catch(Exception e){ e.printStackTrace(); }
System.out.println(rN + "is prepared, waiting for others");
try{ cyclicBarrier.await(); }catch(InterruptedException|BrokenBarrierException e){ e.printStackTrace(); }
System.out.println(rN + "starts running");
}).start();
}
}All three threads print their “ready” message, then they start running together.
Returning a result from a worker thread – The Callable interface allows a thread to produce a value. Wrapped in a FutureTask, the main thread can retrieve the result with get() (which blocks until the computation finishes):
private static void doTaskWithResultInWorker(){
Callable<Integer> callable = new Callable<Integer>(){
@Override public Integer call() throws Exception{
System.out.println("Task starts");
Thread.sleep(1000);
int result = 0;
for(int i=0;i<=100;i++) result += i;
System.out.println("Task finished and return result");
return result;
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
try{
System.out.println("Before futureTask.get()");
System.out.println("Result:" + futureTask.get());
System.out.println("After futureTask.get()");
}catch(InterruptedException|ExecutionException e){ e.printStackTrace(); }
}The output shows the main thread blocked on futureTask.get(), then receiving the computed sum (5050) once the worker finishes.
Overall, the article demonstrates how to coordinate Java threads using basic joins, low‑level wait/notify, higher‑level synchronization utilities, and how to retrieve computation results from background threads.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
