Java for newbies - DeadLock imitation - java

I'm trying to write very simple program which will imitate simple DeadLock, where Thread A waits for Resource A locked by Thread B and Thread B waits for Resource B locked by Thread A.
Here is my code:
//it will be my Shared resource
public class Account {
private float amount;
public void debit(double amount){
this.amount-=amount;
}
public void credit(double amount){
this.amount+=amount;
}
}
This is my runnable which performs Operation on the resource above:
public class BankTransaction implements Runnable {
Account fromAccount,toAccount;
float ammount;
public BankTransaction(Account fromAccount, Account toAccount,float ammount){
this.fromAccount = fromAccount;
this.toAccount = toAccount;
this.ammount = ammount;
}
private void transferMoney(){
synchronized(fromAccount){
synchronized(toAccount){
fromAccount.debit(ammount);
toAccount.credit(ammount);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Current Transaction Completed!!!");
}
}
}
#Override
public void run() {
transferMoney();
}
}
and finally my main class:
public static void main(String[] args) {
Account a = new Account();
Account b = new Account();
Thread thread1 = new Thread(new BankTransaction(a,b,500));
Thread thread2 = new Thread(new BankTransaction(b,a,500));
thread1.start();
thread2.start();
System.out.println("Transactions Completed!!!");
}
}
Why does this code run execute successfully and I don't have and deadLock?

It's got the potential for deadlock - but both locks are acquired so quickly together that one thread can get both before the other has the chance to acquire its first one.
Put another Thread.sleep(500); call between the two synchronized statements and it does deadlock: both threads will enter "their" outer lock, sleep, then when they wake up they'll both find that their "inner" lock is already acquired.
This is due to the fact that you synchronized statements are anti-symetrical : for one thread, the outer synchronized lock is the inner one for the other thread and the other way around.

It's possible that one of the threads will enter both synchronized sections, blocking the other thread entirely until it's finished.

You need to simulate 'unfortunate timing'. Try adding sleep between two locks:
synchronized(fromAccount){
Thread.sleep(2000);
synchronized(toAccount){

Sleeps as suggested by Jon above can introduce non-determinism, you could make it deterministic using some coordinator like a latch instead. To clarify though, I'm thinking of it as a testing problem: how to prove a deadlock every time and that may not be what you're looking for.
See this code for an example and a blog post describing it a little.

The reason of deadlock is that thread A is wait for Thread B to release some resource before A continue; the same to thread B, it wont continue until thread A releases some resource. In other words, A and B wait forever to each other.
In the code snippet, synchronized can block other threads for while because only one thread can execute the block at the moment. thread.sleep() suspend the thread for 500 millisecond, then continue. The wait forever mutually condition doesnt satisfy, that why it is not deadlock.
Following snippet is a good example to illustrate deadlock
public class threadTest{
public class thread1 implements Runnable{
private Thread _th2;
private int _foo;
public thread1(Thread th2){};
public void run(){
for(int i = 0; i<100; i++){foo += foo;};
synchronized(this){this.notify()};
synchronized(_th2){
_th2.wait();
_foo += _th2.foo;
System.out.print(" final result " + _foo);
}
}
}
public class thread2 implements Runnable{
private final thread1 _th1; private int _foo;
public thread2(thread1 th1){};
public void Run(){
synchronized(_th1){_th1.wait()};
synchronized(this){
_foo += th1._foo();
this.notify();
}
}
}
}
}
//just ignore the way to access private variable in the class
Because there is no mechanism assuring the execution order of two threads, it is very possible thread 2 wont receive the notification from thread1 since it starts lately, thus it waits for the notification before continue execution. Same to thread1, it cant do next execution until it receives notification from thread2. both of them wait for each other forever, typical deadlock.

Related

Java synchronization: synchronized, wait(), notify()

I am trying to understand inter-thread communication in Java, and read that the support comes by using: wait(), notify(), notifyAll() methods.
In order thread to execute any of these methods, the thread needs to be owner of object's lock for which thread is invoking (any of these) methods. In addition to this, all these methods needs to be in a synchronized block/method. So far good.
I tried to implement a program in which one thread prints odd numbers, and other thread prints even numbers.
The program works correctly, however, at the same time, it raised few more doubts.
Below is the complete source code of the program which I implemented.
PrintEvenNumThread.java // prints the even numbers
package com.example.multithr.implrun;
import com.example.common.ObjectToWaitOn;
public class PrintEvenNumThread implements Runnable {
private ObjectToWaitOn objectToWaitOn;
public PrintEvenNumThread(ObjectToWaitOn objectToWaitOn) {
this.objectToWaitOn = objectToWaitOn;
}
#Override
public void run() {
int numToPrint = 2;
for (;;) {
synchronized (objectToWaitOn) {
while(objectToWaitOn.getPrintEvenOrOdd() != 2) {
try {
objectToWaitOn.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
objectToWaitOn.print("EvenThread",numToPrint);
numToPrint += 2; // Generate next even number
objectToWaitOn.setPrintEvenOrOdd(1);
objectToWaitOn.notifyAll();
}
}
}
}
PrintOddNumsThread.java // Prints the odd numbers
package com.example.multithr.implrun;
import com.example.common.ObjectToWaitOn;
public class PrintOddNumsThread implements Runnable {
private ObjectToWaitOn objectToWaitOn;
public PrintOddNumsThread(ObjectToWaitOn objectToWaitOn) {
this.objectToWaitOn = objectToWaitOn;
}
#Override
public void run() {
int numToPrint = 1;
for(;;) {
synchronized(objectToWaitOn) {
while(objectToWaitOn.getPrintEvenOrOdd() != 1) {
try {
objectToWaitOn.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
objectToWaitOn.print("OddThread", numToPrint);
numToPrint += 2; // Generate next odd number
objectToWaitOn.setPrintEvenOrOdd(2);
objectToWaitOn.notifyAll();
}
}
}
}
ObjectToWaitOn.java // The "shared" object for inter-thread communication
package com.vipin.common;
public class ObjectToWaitOn {
private int printEvenOrOdd;
public ObjectToWaitOn(int printEvenOrOdd) {
this.printEvenOrOdd = printEvenOrOdd;
}
public int getPrintEvenOrOdd() {
return printEvenOrOdd;
}
public void setPrintEvenOrOdd(int printEvenOrOdd) {
this.printEvenOrOdd = printEvenOrOdd;
}
public void print(String byThread, int numToPrint) {
System.out.println(byThread + ": " +numToPrint);
}
}
PrintEvenOddNumsMainApp.java
package com.example.multithr.main.app1;
import com.example.common.ObjectToWaitOn;
import com.example.multithr.implrun.PrintEvenNumThread;
import com.example.multithr.implrun.PrintOddNumsThread;
public class PrintEvenOddNumsMainApp {
public static void main(String[] args) {
ObjectToWaitOn obj = new ObjectToWaitOn(1); // 1 == odd; 2 == even
PrintEvenNumThread printEvenNumThread = new PrintEvenNumThread(obj);
PrintOddNumsThread printOddNumsThread = new PrintOddNumsThread(obj);
Thread evenNum = new Thread(printEvenNumThread);
Thread oddNum = new Thread(printOddNumsThread);
evenNum.start();
oddNum.start();
}
}
My doubt is:
1) When any of these threads releases lock by calling notifyAll() on object objectToWaitOn (which is shared between these threads), does it release the lock immediately? I have this doubt because these threads are in synchronized block based on objectToWaitOn object; so even if a thread calls the notifyAll(), shouldn't it still hold the lock because it is in synchronized block?
2) When a thread is in waiting condition by calling wait() on objectToWaitOn, and if other thread released the lock by invoking notifyAll(), does the waiting thread waits for lock to release or something else? Doesn't a thread coming out of the synchronized block anyway release the lock on the object it holds; so in above example if a thread is holding lock on objectToWaitOn and comes out of the synchronized block, doesn't it anyway release the lock for objectToWaitOn, and shouldn't based on this the other thread wake up?
Can anyone help me clarify these doubts?
Does it release the lock immediately?
No, it doesn't. The thread continues executing next statements within the synchronisation block.
Shouldn't it still hold the lock because it is in a synchronized block?
Yes, it should. A thread that calls the notify/notifyAll methods must hold the lock and will continue holding it until it leaves the synchronisation block normally or an exception happens:
If execution of the Block completes normally, then the monitor is unlocked and the synchronized statement completes normally.
If execution of the Block completes abruptly for any reason, then the monitor is unlocked and the synchronized statement completes abruptly for the same reason.
JLS-14.19
The notify/notifyAll methods change the state of the threads1 that are waiting on this monitor from State.WAITING to State.RUNNABLE. When the threads are woken up, they can participate in acquiring the lock.
Coming up to the monitor, some of them2 might get the STATE.BLOCKED state and wait until the other thread releases the lock. Note that it doesn't require any notifications from the thread which holds the lock.
The awakened threads will not be able to proceed until the current thread relinquishes the lock on this object. The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
docs
1. In case of notify, it's a single arbitrary chosen thread.
2. Or all of them - if the thread that notified keeps holding the monitor.

Java wait() does not get waked by notify()

Hallo I've been debugging my code for a whole day already, but I just can't see where could be wrong.
I use SerialPortEventListener on a main thread, in a working thread I have a client socket communicating to a server.
Since after this working thread reach return, I still need some wrap up work done in the main thread, i want to create a "pseudothread" that wait in the main thread until the it is notified from the listener onEvent method.
but this pseudothread seems to be waiting forever.
I checked the locked thread pseudoThread, they should have the same object id in the Runnable and in Listener class.
"PseudoThread waiting" got displayed, but PseudoThread awake is never showed.
Console output shows:
PseudoThread waiting
..
..
false notified pseudothread.
PS if I create a lock in Main class with public final Object lock = new Object(); and replace all main.pseudoThread with main.lock, I get java.lang.IllegalMonitorStateException.
private class Pseudo implements Runnable{
Main main;
public Pseudo(Main main) {
this.main = main;
}
#Override
public void run() {
synchronized(main.pseudoThread){
try {
System.out.println("PseudoThread waiting");
main.pseudoThread.wait();
System.out.println("PseudoThread awake");
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
}
}
}
in main method:
public static void main(String[] args) {
Main main = new Main();
main.initArduino();
//more code. including starting the working thread
main.pseudoThread = new Thread(main.new Pseudo(main));
main.pseudoThread.start();
try {
main.pseudoThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void initArduino() {
arduino = new Arduino(this);
if(!arduino.initialize())
System.exit(1);
}
and in the listener class (which also runs in main thread)
//class constructor;
public Arduino(Main Main){
this.main = Main;
}
//listening method
public void serialEvent(SerialPortEvent oEvent){
//some code to interract with working thread.
record();
}
private void record(){
synchronized(main.pseudoThread){
main.pseudoThread.notify();
System.out.println("notified pseudothread.");
}
}
Without looking too deeply into what might actually be happening, I can see that your use of wait()/notify() is all wrong. Probably you are experiencing a "lost notification." The notify() function does nothing if there is no thread waiting for it at the moment when it is called. If your serialEvent() function calls notify() before the other thread calls wait(), then the notification will be lost.
Consider this example:
class WaitNotify() {
private final Object lock = new Object();
private long head = 0;
private long tail = 0;
public void consumer() {
synchronized (lock) {
while(head == tail) {
lock.wait();
}
doSomething();
count head += 1;
}
}
public void producer() {
synchronized (lock) {
tail += 1;
lock.notify();
}
}
}
The essential points are:
(1) The consumer() function waits for some relationship between data to become true: Here, it waits for head != tail.
(2) The consumer() function waits in a loop. There's two reasons for that: (a) Many programs have more than one consumer thread. If consumer A wakes up from the wait(), there's no guarantee that consumer B hasn't already claimed whatever it was that they both were waiting for. And (b) The Java language spec allows foo.wait() to sometimes return even when foo.notify() has not been called. That's known as a "spurious wakeup." Allowing spurious wakeups (so long as they don't happen too often) makes it easier to implement a JVM.
(3) The lock object is the same lock that is used by the program to protect the variables upon which the condition depends. If this example was part of a larger program, you would see synchronized(lock) surrounding every use of head and tail regardless of whether the synchronized code is wait()ing or notify()ing.
If your own code obeys all three of the above rules when calling wait() and notify(), then your program will be far more likely to behave the way you expect it to behave.
As suggested by james it could be lost notification case or it could be that.. Two Threads 1- Your Main Thread and 2- Pseudo thread Are waiting on the same Thread Instance Lock (main.pseudoThread)( Main thread waits on the same lock by calling join method).
Now you are using notify which wakes the Main thread from join method and not the one
waiting in your Pseudo. To check for the second case try calling notifyall in record this will either
confirm the second case or will rule this possibility.
Anyways please refactor your code not to use synch on Thread instance its bad practice. Go for ReentrantLock or CoundDownLatch something.
Usage of notify and wait seem to be incorrect. Method name notify can be a bit misleading because it is not for general purpose "notifying". These methods are used to control the execution of synchronization blocks. Wait will allow some other thread to synchronize with same object while current threads pauses. Basically this is used when some resource is not available and execution can not continue. On the other hand notify will wake one waiting thread wake from wait after notifying thread has completed its synchronized-block. Only one thread can be in synchronized block of the same object at the same time.
If the idea is just keep the main program running until notified then semaphore would be much more appropriate. Something like this.
public void run() {
System.out.println("PseudoThread waiting");
main.semaphore.acquireUninterruptibly();
System.out.println("PseudoThread awake");
}
//...
private void record(){
main.semaphore.release();
}
//...
public static void main(String[] args) {
main.semaphore = new Semaphore(0);
//...
}

Unable to predict given program

public class ThreadStarvation implements Runnable{
long startTime=System.currentTimeMillis();
Timer t;
class RunnerTask extends TimerTask {
public void run(){
if((System.currentTimeMillis()- startTime)< 100000){
System.out.println(Thread.currentThread().getName()+": in timer task run() method"+" : "+Calendar.getInstance().getTime());
}
else
t.cancel();
}
}
public synchronized void synchronizedTimerMethod(){
try{
Thread.sleep(1000);
t=new Timer();
t.schedule(new RunnerTask(), 0, 2000);
}
catch(InterruptedException ie){}
}
public void run(){
synchronizedTimerMethod();
}
public static void main(String[] args) {
ThreadStarvation ts1=new ThreadStarvation();
Thread t1=new Thread(ts1);
Thread t2=new Thread(ts1);
t1.start();
t2.start();
}
}
Three doubts is there in above program :
1) What I want from this program was that when thread t1 starts, goes to synchronized method synchronizedTimerMethod() will lock object ts1 and should locked it until timer object breached the condition. Hence Thread t2 will unable to gain regular access to shared resources ts1 and is unable to make progress and will go into starvation. But this is not happening. Is it not possible with Timer class ? I am novice to it.
2) When thread t1 starts, it goes to synchronized method synchronizedTimerMethod and the object ts1 will be locked. The object ts1 will not be released until timer object is scheduled till condition is breached. But what is happening thread t1 timer object first scheduled start at that time only Thread t2 enters synchronized method synchronizedTimerMethod. Is object ts1 got released due to Timer run method?
3) Also When both thread breached the condition the task is not cancelled, in particular the program stucks or I think it goes into deadlock. WHY?
I rewritten my code as below :
public class ThreadStarvation implements Runnable{
long startTime=System.currentTimeMillis();
final Timer t=new Timer;
class RunnerTask extends TimerTask {
public void run(){
if((System.currentTimeMillis()- startTime)< 100000){
System.out.println(Thread.currentThread().getName()+": in timer task run() method"+" : "+Calendar.getInstance().getTime());
}
else
t.cancel();
}
}
public synchronized void synchronizedTimerMethod(){
try{
Thread.sleep(1000);
t.schedule(new RunnerTask(), 0, 2000);
}
catch(InterruptedException ie){}
}
public void run(){
synchronizedTimerMethod();
}
public static void main(String[] args) {
ThreadStarvation ts1=new ThreadStarvation();
Thread t1=new Thread(ts1);
Thread t2=new Thread(ts1);
t1.start();
t2.start();
}
}
Now I just want that the task should get stopped. For that I made the Timer object as final. Then also the task don't seem to cancel. Is some more modification is needed ? Please help.
1) If you want to enforce fact that t1 enters before t2, then you can't depend on Timer (or rather time) to ensure this (arbitrary interleaving). You should rewrite as a Monitor with a barrier (condition) that only permits t1 to enter first. Then make t1 never release the lock to starve t2 i.e. prevent your synchronized method from terminating (see here).
What is a monitor and how do I create one?
In concurrency, it is a construct used to synchronize your program and make it more predictable i.e. t1 before t2 as illustrated. In this context, synchronization is based on certain conditions/states being satisfied. These conditions act as "barriers" which either prevent or allow a thread to execute. This is very useful as we can use such barriers to not only make our program mode predictable, but also allow us to guarantee certain desirable properties in concurrency i.e. fairness, avoiding deadlock etc. Hence the importance of monitors.
In Java we can create a monitor by defining a class which contains the barrier conditions as private variables. We then only allow changes to those variables through synchronized methods that first test whether the conditions have been fulfilled (barrier).
A simple example to illustrate based on simplifications to your code:
public class ExampleMonitor implements Runnable{
// Condition for our barrier, note it is private
private boolean t1Entered = false;
public synchronized void synchronizedTimerMethod(){
// Test the barrier (check if conditions hold)
while (!t1Entered && !Thread.currentThread().getName().equals("t1")) {
try {
// Did not pass barrier so wait and release lock
wait();
} catch (Exception e) {
// Handle
}
}
// Thread passed barrier and has acquired the lock and can do what it wants
// Update condition so now anyone can enter/pass the barrier
t1Entered = true;
// If this method never terminates then no other thread can enter because lock is never released
long enterTime = System.currentTimeMillis();
while (true) {
System.out.println(Thread.currentThread().getName());
// Let's allow the method to return and thus release the lock after fixed amount of time
// We can then see that threads other than t1 can now acquire the lock
if (System.currentTimeMillis() - enterTime > 5000) {
break;
}
}
// Notify/wake up any waiting threads
this.notifyAll();
}
public void run(){
synchronizedTimerMethod();
// Thread will now terminate
}
public static void main(String[] args) throws InterruptedException {
ExampleMonitor ts1 = new ExampleMonitor();
Thread t1=new Thread(ts1);
t1.setName("t1");
Thread t2=new Thread(ts1);
t2.setName("t2");
t2.start();
// To illustrate how Monitors can be used to ensure
// ordering despite the order threads start in
Thread.sleep(2000);
t1.start();
}
}
Note: this is just an quick example to illustrate and is not ideal i.e. you should not define a monitor that implements Runnable. You can read more about monitors here. Also I recommend working through following book which I also used.
2) See immibis' thorough answer.
3) From the Java doc:
After the last live reference to a Timer object goes away and all outstanding tasks have completed execution, the timer's task execution thread terminates gracefully (and becomes subject to garbage collection). However, this can take arbitrarily long to occur. By default, the task execution thread does not run as a daemon thread, so it is capable of keeping an application from terminating. If a caller wants to terminate a timer's task execution thread rapidly, the caller should invoke the timer's cancel method.
public synchronized void synchronizedTimerMethod(){
try{
Thread.sleep(1000);
t=new Timer();
t.schedule(new RunnerTask(), 0, 2000);
}
catch(InterruptedException ie){}
}
This doesn't do what you think it does. The synchronized method waits for one second, then schedules a RunnerTask to happen every two seconds, then returns. Note that it does not wait for the RunnerTask to run. ts1 is locked only until synchronizedTimerMethod returns, i.e. for one second.
When the "condition is breached" after 100 seconds, you only cancel one Timer, because of a bug. Notice that synchronizedTimerMethod sets t to a new Timer, and that there is only one variable t. After the first task is scheduled, t is a Timer - call it Timer 1. After the second task is scheduled, t is a different Timer - call it Timer 2. Then when 100 seconds is up, both tasks cancel t, which cancels Timer 2 twice.

Use of notify() and notifyAll() doesn't work in the code

I pasted the code below. That is commented enough.
Clear about wait(). When comes here it jumps to another block. That part i am oaky.
My doubt is Why we are using notify and notifyAll(). If you remove these two from below code, it works fine.
class Reader extends Thread{
Calculator c;
//here we didn't write no-arg constructor. Note this.
// one - arg constructor.
public Reader(Calculator calc){
c = calc;
}
public void run(){
synchronized(c){
// 2. Acquiring the object lock and executes this code of block.
try{
System.out.println("Waiting for calculation...");
c.wait();
// 3. Release the object lock and moves to the second synchronize block below
// 6. Later the object get the lock here and moves on.
}catch(InterruptedException e){
}
System.out.println("Total is: "+c.total);
}
}
public static void main(String[] args){
//Instantiating new with no-arg. One more doubt, How this work without no-arg constructor above. Please explain.
Calculator calculator = new Calculator();
//Instantiating new with one-arg
new Reader(calculator).start();
new Reader(calculator).start();
new Reader(calculator).start();
// 1. Once you start here it will goto first synchronized code block above
calculator.start();
}
}
class Calculator extends Thread{
int total;
public void run(){
synchronized(this){
// 4. This block acquires that object lock and executes the code block below.
for(int i=0;i<100;i++){
total +=i;
}
// 5. As per documentation, If we give notify() it will release the object lock to only one thread object of its choice.
// If we use notifyAll(); it will release the object lock to all the three thread object.
notify();
// My doubt here is without using the notify or notifyAll it is working fine.
// As per docs if we use notify() only one object should get the lock. That is also not working here.
}
}
}
General comment: the javadoc of Object#wait states that
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop.
So a waiting thread can wake up without being notified and your design should take that into account by waiting in a loop and checking for an exit condition (cf example in the javadoc).
In your case, however, the issue is slightly different. According to the Thread#join javadoc:
As a thread terminates the this.notifyAll method is invoked. It is recommended that applications not use wait, notify, or notifyAll on Thread instances.
So when your Calculator finishes, it calls this.notifyAll() and wakes up all the waiting threads.
How to fix it?
You should use a separate lock object, similar to: private final Object lock = new Object(); in your Calculator and provide a getter for the Readers.
There is no guarantee about the order in which the threads begin to run. If Calculator runs first then its notify will be lost and no one Reader will be notified.
Here is the corrected version of the above program which makes some sense to notify() and notifyAll().
Here i implemented Runnable instead of extending Threads. Thats the only change i did. Its working perfectly.
class Reader implements Runnable{
Calculator c;
public Reader(Calculator calc){
c = calc;
}
public void run(){
synchronized(c){
try{
System.out.println("Waiting for calculation...");
c.wait();
}catch(InterruptedException e){
}
System.out.println("Total is: "+c.total);
}
}
public static void main(String[] args){
Calculator calculator = new Calculator();
Reader read = new Reader(calculator);
Thread thr = new Thread(read);
Thread thr1 = new Thread(read);
Thread thr2 = new Thread(read);
thr.start();
thr1.start();
thr2.start();
new Thread(calculator).start();
}
}
class Calculator implements Runnable{
int total;
public void run(){
System.out.println("Entered Calculator");
synchronized(this){
for(int i=0;i<20;i++){
total +=i;
}
notifyAll();
}
}
}

Why does the following code result in thread contention

I have the following code
public class Test {
Lock lock = new ReentrantLock();
public static void main(String args[]) throws Exception {
Test t = new Test();
Second second = t.new Second();
second.lock = t.lock;
Thread thread = new Thread(second);
thread.start();
Thread.sleep(2000);
try {
t.lock.lock();
System.err.println("got the lock");
} finally {
second.shutdown = true;
t.lock.unlock();
}
}
private class Second implements Runnable {
Lock lock;
volatile boolean shutdown = false;
int i = 0;
public void run() {
while (!shutdown) {
try {
lock.lock();
System.out.println("In second:" + i++);
} finally {
lock.unlock();
}
}
}
}
}
I read here that there is a concept of fair and unfair lock, but making locks fair has a big performance impact and nevertheless shouldn't the above code give some fairness to the current thread.
While actual execution of the above code, the second thread runs forever (gave way for main thread after 545342 iterations)
Is there something I am doing wrong here? Can anyone explain this behavior?
Basically without making the lock fair, the second thread is unlocking and managing to reacquire the lock before the first thread gets a chance to do so. After your large number of iterations, it must have been pre-empted between the "unlock" and the "lock", giving your first thread an opportunity to get in and stop it.
Fundamentally though, you simply shouldn't have code like that in the second thread - under what real life situation do you want to repeatedly release and acquire a lock doing no work between the two, beyond checking a flag? (And if you do want to do that, why do you want to require that a "shutting down" thread acquires the same lock in order to set the flag?)

Categories