Boolean flag example
I love this example. It starts two threads that share a boolean flag:
public class UntilYouUpdateIt
{
public static boolean flag = true;
public static void main(String[] args) throws InterruptedException
{
Thread t1 = new Thread(()->
{
while(flag){}
System.out.println("end");
});
t1.start();
Thread.sleep(100);
Thread t2 = new Thread(()->
{
flag = false;
System.out.println("changed");
});
t2.start();
}
}
First thread will loop until flag
is false, which happens in the first line of the 2nd thread. The program won't ever finish, and it's ouput would be:
changed
2nd thread dies, meanwhile the 1st one will loop forever.
Why is it happenning? Compiler opmitizations
. Thread1 will never check again flag's value, as:
- the operation inside the loop is cheap (nothing to do)
- The compiler knows there's no other entity that can modify the flag value (as the first thread doesn't, and the 2nd one is already dead). So it assumes flag will always be true.
In other words, Thread1 will always be reading the flag
value from the cache
, where it is set as true
.
Two ways to solve/test this:
Thread t1 = new Thread(()->
{
while(flag)
{
System.out.print("I'm loopinnnng");
}
System.out.println("end");
});
If some "heavy" operation is included (int i=1
or similar would'nt work neither), such as a System
call, the optimizer will be a little more careful, checking the flag
boolean in order to know if he's not wasting resources. The output would be:
I'm loopinnnng
I'm loopinnnng
I'm loopinnnng
I'm loopinnnng
I'm loopinnnng
(....)
changed
end
or
I'm loopinnnng
I'm loopinnnng
I'm loopinnnng
I'm loopinnnng
I'm loopinnnng
(....)
end
changed
Depending which thread was assigned the cpu time at the end.
The correct solution to avoid these kind of deadlocks, when working with boolean variables, should be including the volatile
keyword.
volatile
tells the compiler: do not try to optimize when this variable is involved.
So, this same code with just that keyword added:
public class UntilYouUpdateIt
{
public static volatile boolean flag = true;
public static void main(String[] args) throws InterruptedException
{
Thread t1 = new Thread(()->
{
while(flag){}
System.out.println("end");
});
t1.start();
Thread.sleep(100);
Thread t2 = new Thread(()->
{
flag = false;
System.out.println("changed");
});
t2.start();
}
}
Will output:
changed
end
or
end
changed
The result is both threads finishing correctly, avoiding any deadlock.
Unordered locks example
This one is a basic one:
public void methodA()
{
//...
synchronized(lockA)
{
//...
synchronized(lockB)
{
//...
}
}
}
public void methodB()
{
//...
synchronized(lockB)
{
//...
synchronized(lockA)
{
//...
}
}
}
This methods would probably create a great deadlock if called by many threads. This is because the objects are locked in different order. This is one of the most common reasons of deadlocks, so if you want to avoid them, be sure that the locks are aquired in order.