I have an unexpected (for me at least) output with this code
public class Test {
static boolean condition = false;
void runme() {
var reader = new Runnable() {
@Override
public void run() {
synchronized (this) {
System.out.println("waiting for condition");
while (!condition) {}
System.out.println("condition is true");
}
}
};
var writer = new Runnable() {
@Override
public void run() {
synchronized (this) {
System.out.println("condition is set to true");
condition = true;
}
}
};
new Thread(reader).start();
new Thread(writer).start();
}
public static void main(String[] args) {
new Test().runme();
}
}
Based on the documentation, I expected a deadlock if the reader
object starts first, since
this
(entering the synchronized block)this
lock, to get into its own synchronized blockHowever, on some runs of the code I get the output
waiting for condition
condition is set to true
condition is true
Am I missing something or have I misunderstood how synchronized blocks/methods work?
The two synchronized (this)
statements reference the Runnable
anonymous classes.
So the synchronizations of the two Runnable
instances don't operate on the same lock.
You have to synchronize on the outer class instance to lock on the same monitor such as :
synchronized (Test.this) {...}
Additionally, note that by using a lambda to implement the Runnable
functional interface such as :
var writer = () -> {
synchronized (this) {
System.out.println("condition is set to true");
condition = true;
}
};
you could keep the actual syntax (synchronized (this)
) as this
in this case doesn't refer the anonymous class that doesn't exist but refers the outer instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With