Ensure the thread execution order
Introduction
This post demonstrates how to ensure thread execution order in Java using Thread.join and CountDownLatch.
Environments
- Java 1.8
Via the Thread.join method
According to the Java API documentation, Thread.join
allows the current thread to wait for another thread to complete. The key methods are:
public final void join(long millis) throws InterruptedException
: Waits at mostmillis
milliseconds for the thread to terminate.public final void join() throws InterruptedException
: Waits indefinitely for the thread to terminate.
Thread.join example
We will create three threads and ensure they execute in the following order:
- Thread2 starts as soon as Thread1 ends.
- Thread3 starts 1 second after Thread2 starts.
- The main thread waits for all threads to complete.
Create a custom Thread class
Here is a custom thread class with name and sleep functionality:
static class MyThread extends Thread { private final String name;
public MyThread(String name) { super(name); this.name = name; }
public void run() { try { log.info("thread " + name + " started"); Thread.sleep(3000); } catch (InterruptedException e) { log.error("", e); } log.info("thread " + name + " end"); }}
Use Thread.join to control the order of thread execution
Thread thread1 = new MyThread("thread1");Thread thread2 = new MyThread("thread2");Thread thread3 = new MyThread("thread3");
log.debug("join test start...");
thread1.start();thread1.join(); // Wait until thread1 is donethread2.start();thread2.join(1000); // Wait at most 1 secondthread3.start();
thread3.join(); // Wait for all threads to completelog.debug("join test all done");
Console Output
20:54:54.051 [main] DEBUG java8.learn.thread.thread_join.JoinTester - join test start...20:54:54.055 [thread1] INFO java8.learn.thread.thread_join.JoinTester - thread thread1 started20:54:57.060 [thread1] INFO java8.learn.thread.thread_join.JoinTester - thread thread1 end20:54:57.061 [thread2] INFO java8.learn.thread.thread_join.JoinTester - thread thread2 started20:54:58.062 [thread3] INFO java8.learn.thread.thread_join.JoinTester - thread thread3 started20:55:00.064 [thread2] INFO java8.learn.thread.thread_join.JoinTester - thread thread2 end20:55:01.065 [thread3] INFO java8.learn.thread.thread_join.JoinTester - thread thread3 end20:55:01.065 [main] DEBUG java8.learn.thread.thread_join.JoinTester - join test all done
CountDownLatch Example
Now we will use CountDownLatch
to ensure a consumer thread waits for a producer thread to complete.
What is CountDownLatch?
CountDownLatch
is a synchronization aid that allows one or more threads to wait until a set of operations completes. Key methods include:
countDown()
: Decrements the latch count.await()
: Causes the current thread to wait until the latch count reaches zero.
The CountDownLatch property
private static CountDownLatch latch = new CountDownLatch(1);
The producer thread
static class MyProducerThread extends Thread { private final String name;
public MyProducerThread(String name) { super(name); this.name = name; }
public void run() { try { log.info("producer thread " + name + " started"); Thread.sleep(3000); latch.countDown(); // Decrement the latch } catch (InterruptedException e) { log.error("", e); } log.info("producer thread " + name + " end"); }}
The consumer thread
static class MyConsumerThread extends Thread { private final String name;
public MyConsumerThread(String name) { super(name); this.name = name; }
public void run() { try { log.info("consumer thread " + name + " start waiting..."); latch.await(); // Wait for the latch to reach zero log.info("consumer thread " + name + " started"); } catch (InterruptedException e) { log.error("", e); } log.info("consumer thread " + name + " end"); }}
The consumer and producer threads execution in order
Thread threadProducer = new MyProducerThread("producer1");Thread threadConsumer = new MyConsumerThread("consumer1");
log.debug("CountDown test start...");
threadProducer.start();threadConsumer.start();
threadConsumer.join();
log.debug("CountDown test all done");
Console Output
21:12:07.829 [main] DEBUG java8.learn.thread.thread_join.JoinTester - CountDown test start...21:12:07.833 [producer1] INFO java8.learn.thread.thread_join.JoinTester - producer thread producer1 started21:12:07.833 [consumer1] INFO java8.learn.thread.thread_join.JoinTester - consumer thread consumer1 start waiting...21:12:10.837 [producer1] INFO java8.learn.thread.thread_join.JoinTester - producer thread producer1 end21:12:10.837 [consumer1] INFO java8.learn.thread.thread_join.JoinTester - consumer thread consumer1 started21:12:12.841 [consumer1] INFO java8.learn.thread.thread_join.JoinTester - consumer thread consumer1 end21:12:12.841 [main] DEBUG java8.learn.thread.thread_join.JoinTester - CountDown test all done
Summary
In this post, we explored two methods to ensure thread execution order in Java: Thread.join
and CountDownLatch
. Both methods are effective for synchronizing threads, but they serve slightly different use cases. Thread.join
is simpler and ideal for linear thread dependencies, while CountDownLatch
is more flexible and suitable for coordinating multiple threads.
Final Words + More Resources
My intention with this article was to help others who might be considering solving such a problem. So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Java threads
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!