简体   繁体   中英

Does Thread.join() release the lock? Or continue to hold it?

As I understand it, internally obj.join() calls wait() . This means that join() always releases the lock (because wait() always releases the lock after being called).

The API doc explains :

This implementation uses a loop of this.wait calls conditioned on this.isAlive . As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait , notify , or notifyAll on Thread instances.

People here on SO say that join() does not release any lock because the API does not mention it explicitly. But this logic seems strange to me.

Here is the main logic from join() 's code:

 while (isAlive()) {
            wait(0);
        }

This site further adds to the confusion (I think they are mistaken):

3) The third difference between the wait() and join() methods is that when a thread calls the wait() method it releases any lock held for the object on which wait() is called, but calling the join() method doesn't release any monitor or lock.

wait releases the monitor held on the object which wait is invoked on, but not any other monitors.

The current thread must own this object's monitor. The thread releases ownership of this monitor and waits [...].

In other words, given the following:

synchronized (a) {
    synchronized (b) {
        b.wait();
    }
}

At b.wait() , the current thread releases b 's monitor, but not a 's monitor.

If t.join() is implemented using t.wait() internally, then t 's monitor is released while waiting, but not any other monitor.

This join implementation is a case of leaky abstraction , by the way. If Thread used a private final Object monitor; to wait on instead, we could say that join released no monitors, even if it used wait internally without us knowing. There would be no reason to document the implementation detail of using wait , because the monitor would be inaccessible to us, so we would not need to know about it.

The reason that we know join uses wait internally is that the people who originally wrote the method chose a monitor which is accessible to us. This created the need to reveal the implementation details. join is not really supposed to release monitors from our perspective, just wait for a thread to complete, but an implementation was chosen which required us to know more about it than we should.

Though the excellent answer from @Radiodef clarifies & elaborates the leaky abstraction shortcoming, in simpler terms to answer @vrinchvucz confusion the answer is,

Yes, when a thread invokes t.join it does acquire and release 'a' monitor lock. That monitor lock is that of the thread t itself since the implementation of join method on Thread class implemented it by using this.wait inside of the synchronized join method which is the leaky abstraction issue that @Radiodef points to.

Thus unless the thread acquires the monitor lock of t itself before it invokes t.join we can say that NO client/user acquired monitor locks are released in the t.join invocation (because the monitor lock in question is NOT any that the client/user code acquired in the thread that invoked t.join ).

This since as clearly stated in the docs for Object#wait

Note that the wait method, as it places the current thread into the wait set for this object, unlocks only this object; any other objects on which the current thread may be synchronized remain locked while the thread waits.

Which is why the docs for Thread#join does not mention anything about locks being released while still giving the implementation details regarding the use of this.wait .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM