Does Thread#join() let other threads through synchronized blocks? - java

The Object#wait() method has this funny property that it will allow other threads to enter it's synchronized block while it is blocked in it. Example (assume thread 1 runs first):
Thread 1:
synchronized(someLock)
{
wait();
}
Thread 2:
synchronized(someLock)
{
notify();
}
The fact that thread 2 is able to wake up thread 1 means that thread 2 entered the synchronized block even though some other thread was in a synchronized block on the same object. That's fine with me but I'm wondering if that happens only for Object#wait() or for all methods that would make the thread "wait" (Thread#sleep, Thread#join). In my case I care about Thread#join because if the behavior is the same as Object#wait() it would break my code:
private void waitForClose()
{
try
{
// if one thread is waiting in join the other will wait on the semaphore
synchronized(joinLock)
{
if(outputThread != null && Thread.currentThread() != outputThread)
outputThread.join();
outputThread = null;
if(inputThread != null && Thread.currentThread() != inputThread)
inputThread.join();
inputThread = null;
}
}
catch(InterruptedException ex)
{
logger.error("Interrupted Exception while waiting for thread to join in " + name, ex);
}
}
So is it possible that multiple threads enter this synchronized block because of the join call putting the thread in a waiting state?

First of all the wait and notify mechanism is not really that funny. It is the most rudimentary way of coordinating two or more threads in Java. It is important to understand what is happening here:
Thread 1:
synchronized (someLock) {
System.out.println("Thread 1 going to wait ...");
someLock.wait();
System.out.println("Threads 1 got notified.");
}
Thread 2:
synchronized (someLock) {
System.out.println("Notifying");
someLock.notify();
System.out.println("Exiting block.");
}
The wait() call will relinquish the lock allowing another thread to take hold of it. At this point, thread 1 will not be able to proceed even if it gets notified. This documentation clearly states this:
The awakened thread will not be able to proceed until the current
thread relinquishes the lock on this object.
So it is only after thread 2 exits the synchronized block that thread 1 will proceed with the code after the wait().
Thread.join() is syntactic sugar, a helper method that underneath the hood makes use of the same wait and notify / notifyAll() methods. In fact the javadoc warns against using wait and notify on Thread objects, not to interfere with this mechanism.
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.
Thread.sleep() is unrelated to wait and notify. It does not need an object's lock, and does not need to be in a synchronized block.
Your code seems to be synchronizing on an object called joinLock while the outputThread.join() will be synchronizing and waiting on the outputThread object. They are unrelated. If anything you might risk a dead lock if outputThread is synchronizing on joinLock. Without the code for the outputThread I can't say.

Related

Why calling notify in Java requires holding the lock?

Thread thread = new Thread(() -> {
synchronized (this){
try {
this.wait();
System.out.println("Woke");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
this.notify();
When calling notify it says
java.lang.IllegalMonitorStateException: current thread is not owner
The typical usage of notify is that you call it and then you release the lock implicitly (by leaving the synchronized block) so that the waiting threads may re-acquire the lock.
But code above calls notify even before it has the lock, so other threads can just try to acquire the lock, why not? I think the holding the lock is not necessary.
I think the holding the lock is not necessary.
It is necessary because the javadoc for Object.notify() says it is necessary. It states:
"This method should only be called by a thread that is the owner of
this object's monitor. A thread becomes the owner of the object's
monitor in one of three ways:
By executing a synchronized instance method of that object.
By executing the body of a synchronized statement that synchronizes on the object.
For objects of type Class, by executing a synchronized static method of that class."
But your real question is why is it necessary? Why did they design it this way?
To answer that, we need to understand that Java's wait / notify mechanism is primarily designed for implementing condition variables. The purpose of a condition variable is to allow one thread to wait for a condition to become true and for another thread to notify it that this has occurred. The basic pattern for implementing condition variables using wait() / notify() is as follows:
// Shared lock that provides mutual exclusion for 'theCondition'.
final Object lock = new Object();
// Thread #1
synchronized (lock) {
// ...
while (! theCondition) { // One reason for this loop will
// become later ...
lock.wait();
}
// HERE
}
// Thread # 2
synchronized (lock) {
// ...
if (theCondition) {
lock.notify();
}
}
This when thread #1 reaches // HERE, it knows that theCondition is now true. Furthermore it is guaranteed the current values variables that make up the condition, and any others controlled by the lock monitor will now be visible to thread #1.
But one of the prerequisites for this actually working is that both thread #1 and thread #2 are synchronized on the same monitor. That will guarantee the visibility of the values according to a happens before analysis based on the Java Memory Model (see JLS 17.4).
A second reason that the above needs synchronization is because thread #1 needs exclusive access to the variables to check the condition and then use them. Without mutual exclusion for the shared state between threads #1 and #2, race conditions are possible that can lead to a missed notification.
Since the above only works reliably when threads #1 and #2 hold the monitor when calling wait and notify, the Java designers decided to enforce this in implementations of the wait and notify methods themselves. Hence the javadoc that I quoted above.
Now ... your use-case for wait() / notify() is simpler. No information is shared between the two threads ... apart from the fact that the notify occurred. But it is still necessary to follow the pattern above.
Consider the consequences of this caveat in the javadoc for the wait() methods:
"A thread can wake up without being notified, interrupted, or timing out, a so-called "spurious wakeup". While this will rarely occur in practice, applications must guard against it ..."
So one issue is that a spurious wakeup could cause the child thread to be woken before the main thread's sleep(...) completes.
A second issue is that is the child thread is delayed, the main thread may notify the child before the child has reached the wait. The notification then be lost. (This might happen due to system load.)
What these issues mean is that your example is incorrect ... in theory, if not in reality. And in fact, it is not possible to solve your problem using wait / notify without following the pattern above/
A corrected version of your example (i.e. one that is not vulnerable to spurious wakeups, and race conditions) looks like this:
final Object lock = new Object;
boolean wakeUp = false;
Thread thread = new Thread(() -> {
synchronized (lock){
try {
while (!wakeUp) {
this.wait();
}
System.out.println("Woke");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
synchronized (lock) {
wakeUp = true;
this.notify();
}
Note that there are simpler and more obviously correct ways to do this using various java.concurrent.* classes.
The case where using synchronized makes sense is where the thing using the lock has state that needs to be protected. In that case the lock has to be held while notifying because there are going to be state changes that go along with the notification, so that requiring notify to be called with the lock makes sense.
Using wait/notify without state that indicates when the thread should wait is not safe, it allows race conditions that can result in hanging threads, or threads can stop waiting without having been notified. It really isn't safe to use wait and notify without keeping state.
If you have code that doesn't otherwise need that state, then synchronized is an overcomplicated/tricky/buggy solution. In the case of the posted code example you could use a CountdownLatch instead, and have something that is simple and safe.

How does JVM notify a thread blocked by `join()`?

The join() method waits for a thread to die. it use wait to do this.
if (millis == 0) {
while (isAlive()) {
wait(0);
}
}
So when the thread exits, how can it notify threads in wait set.
I try to find code in JDK source code, but failed. Can anyone show me the relevant code snippets?
when a thread in wait set, it may check isAlive() so many times for its timeslice, is this a waste?
if isAlive() is false, it just return, that thread is already in wait set. Is the while(isAlive()) necessary?
I try to find code in JDK source code, but failed. Can anyone show me the relevant code snippets?
The pathname for the Thread class in the OpenJDK jdk8u source tree is jdk/src/share/classes/java/lang/Thread.java. The code for join() is below.
The native code where the notifyAll occurs is in Thread::exit in hotspot/src/share/vm/runtime/thread.cpp.
For other releases the paths may be different. (The find command is your friend.)
When a thread in wait set, it may check isAlive() so many times for its timeslice, is this a waste?
That is incorrect.
The "wait set" argument is incorrect. If the current thread can call isAlive() it is not in any wait set. It will only be in the "wait set" for the target Thread when it is in a wait(...) call. It is removed from the "wait set" when the current thread is notified.
To reiterate, a thread t1 is in the "wait set" of another thread t2 when t1 is executing t2.wait(...).
A wait(0) call means "wait until notified without a timeout". (It does NOT mean the same thing assleep(0) or yield()!) Therefore, this is not a busy loop.
The loop will usually go around zero or one time only. (But see the next part of my answer.)
If isAlive() is false, it just return, that thread is already in wait set. Is the while(isAlive()) necessary?
Your "wait set" logic is incorrect (as above).
The loop is necessary. It is possible for any application code that has a reference to the target Thread object to call Object.notify() on that it. That causes the wait(0) to return. But since this "wake up" is spurious, it is necessary to check that the target Thread has actually ended (by calling isAlive()) and maybe waiting again.
This could happen repeatedly ... if application code is doing something silly ... but it shouldn't.
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
Most of the implementation of Thread is in native code. That is where the notifyAll that wakes up the joining threads is made.
To answer your questions:
wait() is a native method and uses System code. There is no Java code for that.
wait() is not a means to wait for a Thread but to synchronize on a certain object. Wait() is the wrong method to pause a thread, you need to use sleep().
The counterpart of wait() is notify() or notifyAll(). This will wake up Threads which wait for the calling object. Wait() and notify are part of the Object.class and need a synchronization on the object.
A Thread is alive as long as its run method is executing. If you join a thread the calling thread will automatically halt.
If you want to let a thread wait then use Thread.sleep.
Thread t1 = new Thread(){
public void run(){
try {
sleep(5000);
} catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("I'm done");
}
}
t1.start();
//The calling thread will wait here for 5 sec.
t1.join();

Using this.wait() inside run() in a synchronized block

I have this code:
public class Nit extends Thread {
public void run() {
try {
synchronized(this) {
this.wait();
}
System.out.println("AAA");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Nit n = new Nit();
n.start();
synchronized(n) {
n.notify();
}
}
}
When I run it from cmd it never exits like it is an infinite loop. I don't understand why. Only thing i can think of is that Nit n is still waiting but I don't get why?
You are observing a race condition. You notify before the wait happens. Therefore the wait sits there and waits forever.
If you would invoke this code often enough, you might see it passing sometimes - when the new thread advanced faster then the main thread. One way to make the example work: try adding a call to Thread.sleep(1000) or so before calling notify(). Alternatively, even a println() call on the main thread (before the notify() might change timing enough).
Beyond that: such subtleties are the main reason why you actually avoid using the "low level" primitives such as as wait/notify. Instead, you use the powerful abstractions (like queues) that standard APIs have to offer.
The notify method tells the scheduler to pick a thread to notify, choosing from only those threads that are currently waiting on the same lock that notify was called on.
In this case the n thread doesn't start waiting until after the notification has already happened, so nothing ever wakes the thread up from waiting. You may have assumed that waiting threads will see notifications made before they started waiting, or that the JVM would have to give the n thread CPU time before the main thread proceeds past the call to start, but those assumptions aren't valid.
Introduce a condition flag as an instance member of Nit:
public class Nit extends Thread {
boolean notified = false;
and change Nit's run method to check it:
synchronized (this) {
while (!notified) {
wait();
}
}
Then add a line to the main method so that the main thread can set the flag:
synchronized (n) {
n.notified = true;
n.notify();
}
This way the notify can still happen before n starts waiting, but in that case n will check the flag, see it's true already, and skip waiting.
See Oracle's guarded blocks tutorial:
Note: Always invoke wait inside a loop that tests for the condition being waited for.
Also the API documentation (see Thread.join) discourages the practice of locking on thread objects.

Can a synchronized block/method be interrupted?

While I know the theoretical differences between Re-EntrantLocks and synchronized, I'm confused to the below point.
See this statement from an article on Javarevisited comparing synchronized and Lock objects:
One more worth noting difference between ReentrantLock and
synchronized keyword in Java is, ability to interrupt Thread while
waiting for Lock. In case of synchronized keyword, a thread can be
blocked waiting for lock, for an indefinite period of time and there
was no way to control that. ReentrantLock provides a method called
lockInterruptibly(), which can be used to interrupt thread when it is
waiting for lock. Similarly tryLock() with timeout can be used to
timeout if lock is not available in certain time period.
As per the above statement, I did try interrupting the Thread waiting() on synchronized method (i.e blocking wait) and it did throw an InterruptedException. But this behavior is contradictory with what is stated in the above statement.
// this method is called from inside run() method of every thread.
public synchronized int getCount() {
count++;
try {
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " gets " + count);
} catch (InterruptedException e) {
e.printStackTrace();
}
return count;
}
....
....
t1.start();
t2.start();
t3.start();
t4.start();
t2.interrupt();
Here is the output that I got :
Thread 1 gets 1
Thread 4 gets 2
Thread 3 gets 3
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at locks.SynchronizedLockInterrupt.getCount(SynchronizedLockInterrupt.java:10)
at locks.SynchronizedLockInterrupt$2.run(SynchronizedLockInterrupt.java:35)
at java.lang.Thread.run(Unknown Source)
I'm confused if my example is not correct or the quoted statement about synchronized() is incorrect?
Without the rest of the code this question might not be fully answered.
What, I think, you're being confused with here is that you're seeing that, whilst the code would imply you cannot "interrupt" a thread that's blocked on a synchronized lock you are seeing that your count variable seems to be unaffected by the thread which is supposed to have entered into this method.
Important to note that you can technically "interrupt" a blocked thread, as in you can call interrupt() on it and this will set the interrupted flag. Just because a Thread has the interrupted flag set does not mean that it cannot execute any more code. Simply, when it get's to the next code that checks for an interrupted state, that code will likely throw an InterruptedException whilst clearing the flag at the same time. If the person catching the exception intends to do more work, it's their (almost moral) duty to re-set the flag or throw the same.
So, yes, in your example, you are catching the exception that has been thrown by .sleep() on entry, likely before the thread was sleep-ed, you then print the stack trace that proves that.
The outstanding question that might be causing confusion for you; why, then, did my count not increment if this code was allowed to run until the .sleep() method call?
The answer is that the count variable was incremented, you just didn't see the result.
synchronized in Java does not guarantee order and can lead to starvation so t2 just happened to be executed last and you never checked the count before you slept to see that it was already 3
So to answer your question, the documentation is correct and the behaviour is correct.
Interrupting a thread which is waiting "uninterruptedly" on a Lock , ReentrantLock or synchronized block will merely result in the thread waking up and seeing if it's allowed to take the lock yet, by whatever mechanism is in place in the defining lock, and if it cannot it parks again until it is interrupted again or told it can take the lock. When the thread can proceed it simply proceeds with its interrupted flag set.
Contrast to lockInterruptibly where, actually, if you are interrupted, you do not ever get the lock, and instead you "abort" trying to get the lock and the lock request is cancelled.
lock and lockInterruptibly can be mixed use on the same ReentrantLock as the lock will manage the queue and skip requests that were CANCELLED by a finally statement because they were interrupted when waiting on a lock.
In summary:
You can almost always interrupt a thread.
The interrupt flag is usually only cleared on a thread by code that documents that it clears the flag when throwing the InterruptedException , but not all code documents this (lockInterruptibly on ReentrantLock does, but not the same on AbstractQueuedSynchronizer which powers the lock).
Interrupting a thread has different behaviour depending on what it is doing at the time;
A parked thread will be un-parked and have it's flag set, usually then cleared
A thread waiting on a lock / synchronized block will eventually get into the code but with interrupted flag set
A thread waiting on a lockInterruptibly or a get on a future etc will be unparked and behave as documented, aborting the lock acquisition.
synchronized is an intrinsic lock which is beyond the control of JDK.
Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.") Intrinsic locks play a role in both aspects of synchronization: enforcing exclusive access to an object's state and establishing happens-before relationships that are essential to visibility.
When a thread invokes a synchronized method, it automatically acquires the intrinsic lock for that method's object and releases it when the method returns. The lock release occurs even if the return was caused by an uncaught exception.
In your example, you are actually interrupting the sleep as JDK doc mentions.
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
More details about how interrupt() works.
Many methods that throw InterruptedException, such as sleep, are designed to cancel their current operation and return immediately when an interrupt is received.
If have added a simple example to make it clear.
In your example you have already aquired the lock, see your stacktrace.
The code is self explaining.
The problem with synchronized is that it is no interruption point, whereas lock.lockInterruptibly() is. Note that lock.lock() is also not an interruption point.
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Foo {
public static void main(String[] args) throws InterruptedException {
// for the example with synchronized
Object monitor = new Object();
// for the example with locks
Lock lock = new ReentrantLock();
// iam lazy, just use both lock and motitor for this example
Thread one = new Thread(() -> {
lock.lock();
try {
synchronized (monitor) {
System.out.println("Thread one entered monitor");
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Thread one interrupted");
Thread.currentThread().interrupt();
}
}
} finally {
lock.unlock();
}
});
// uncomment to use the monitor object
// Thread two = new Thread(() -> {
// synchronized (monitor) {
// System.out.println("Thread two entered monitor");
// }
// });
Thread two = new Thread(() -> {
try {
lock.lockInterruptibly();
try {
System.out.println("Thread one entered lock");
} finally {
lock.unlock();
}
} catch (InterruptedException e) {
System.out.println("Thread two interrupted while waiting for lock");
Thread.currentThread().interrupt();
}
});
// start thread one
one.start();
// wait for the thread to start, too lazy to implement notifications
Thread.sleep(1000);
// start thread two
two.start();
// interrupting will wait until thread one finished
two.interrupt();
}
}
If you remove "Thread.sleep(3000)", your 'getCount()' method will not throw exception.
You can only interrupt a thread either in sleep or wait in case of Synchronised method
You're not interrupting the synchronization, you're interrupting the sleep().

Why should the notify method be inside a synchronized block?

Consider the following code :-
class CalculateSeries implements Runnable{
int total;
public void run(){
synchronized(this){ // *LINE 1*
for(int i = 1; i <= 10000; i++) {
total += i;
}
notify(); //Notify all the threads waiting on this instance of the class to wake up
}
}
}
Another class is waiting on an instance of this class by getting the lock on it inside a synchronized block. But if I don't keep the code in run method in a synchronized block, then I get IllegalMonitorStateException.
notify() should mean to give signal to all the threads waiting. Then why should it be inside synchronized block?
notify() should mean to give signal to all the threads waiting.
Actually, no. It signals one arbitrarily chosen waiting thread. notifyAll() signals all of them.
Then why should it be inside synchronized block?
Because waiting doesn't happen for its own sake. You check for a condition and if it's not met, you wait until someone tells you it may now be met (then you check again). Without synchronization, you would have race conditions between checking the condition and actually waiting.
if notify() method is not within synchronized block then it would be useless to place wait() into synchronized block.
Take scenario of producer-consumer model, producer and consumer both the methods will execute concurrently because one of them is not synchronized. There will be a race condition.

Categories