Use of join in java
Introduction
join() is a method we often use in java that sets the current thread to the WAITTING state and then waits for the calling thread to finish executing or be interrupted.
Definition
join() is a method defined in Thread, let’s look at his definition.
/**
* Waits for this thread to die.
*
* <p> An invocation of this method behaves in exactly the same
* way as the invocation
*
* <blockquote>
* {@linkplain #join(long) join}{@code (0)}
* </blockquote>
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final void join() throws InterruptedException {
join(0);
}
Application
Let’s see how join is used. Usually we need to call thread B.join() in thread A:
public class JoinThread implements Runnable{
public int processingCount = 0;
JoinThread(int processingCount) {
this.processingCount = processingCount;
log.info("Thread Created");
}
@Override
public void run() {
log.info("Thread " + Thread.currentThread().getName() + " started");
while (processingCount > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.info("Thread " + Thread.currentThread().getName() + " interrupted");
}
processingCount--;
}
log.info("Thread " + Thread.currentThread().getName() + " exiting");
}
@Test
public void joinTest()
throws InterruptedException {
Thread t2 = new Thread(new JoinThread(1));
t2.start();
log.info("Invoking join");
t2.join();
log.info("Returned from join");
log.info("t2 status {}",t2.isAlive());
}
}
We call t2.join() in the main thread, then the main thread will wait for t2 to finish execution, we see the following output.
06:17:14.775 [main] INFO com.javaisland.JoinThread - Thread Created
06:17:14.779 [main] INFO com.javaisland.JoinThread - Invoking join
06:17:14.779 [Thread-0] INFO com.javaisland.JoinThread - Thread Thread Thread-0 started
06:17:15.783 [Thread-0] INFO com.javaisland.JoinThread - Thread Thread Thread-0 exiting
06:17:15.783 [main] INFO com.javaisland.JoinThread - Returned from join
06:17:15.783 [main] INFO com.javaisland.JoinThread - t2 status false
When the thread has finished executing or has not yet started executing, join() will immediately return.
Thread t1 = new SampleThread(0);
t1.join(); //returns immediately
join has two other methods with time parameters.
public final void join(long millis) throws InterruptedException
public final void join(long millis,int nanos) throws InterruptedException
If the called thread does not return within the given time, the main thread will continue to execute.
@Test
public void testJoinTimeout()
throws InterruptedException {
Thread t3 = new Thread(new JoinThread(10));
t3.start();
t3.join(1000);
log.info("t3 status {}", t3.isAlive());
}
The above example will output.
06:30:58.159 [main] INFO com.javaisland.JoinThread - Thread Created
06:30:58.163 [Thread-0] INFO com.javaisland.JoinThread - Thread Thread Thread-0 started
06:30:59.172 [main] INFO com.javaisland.JoinThread - t3 status true
Join() also has a happen-before feature, which is that if thread t1 calls t2.join(), then when t2 returns, all t2’s changes will be visible to t1.
We also mentioned this happen-before rule when we talked about the volatile keyword earlier, Application of Volatile
.
Let’s look at the following example.
@Test
public void testHappenBefore() throws InterruptedException {
JoinThread t4 = new JoinThread(10);
t4.start();
// not guaranteed to stop even if t4 finishes.
do {
log.info("inside the loop");
Thread.sleep(1000);
} while ( t4.processingCount > 0);
}
As we run it, we can see that the while loop keeps going even though the variable in t4 has gone to 0.
So if we need to use it in this case, we need to use join(), or some other synchronization mechanism.