java code for deadlock situation? - java

here is the code
public class TestDeadlockExample1 {
public static void main(String[] args) {
final String resource1 = "xyz";
final String resource2 = "pqr";
// t1 tries to lock resource1 then resource2
Thread t1 = new Thread() {
public void run() {
synchronized (resource1) {
System.out.println("Thread 1: locked resource 1");
try { Thread.sleep(10000);} catch (Exception e) {}
synchronized (resource2) {
System.out.println("Thread 1: locked resource 2");
}
}
}
};
// t2 tries to lock resource2 then resource1
Thread t2 = new Thread() {
public void run() {
synchronized (resource2) {
System.out.println("Thread 2: locked resource 2");
try { Thread.sleep(10000);} catch (Exception e) {}
synchronized (resource1) {
System.out.println("Thread 2: locked resource 1");
}
}
}
};
t1.start();
t2.start();
System.out.println("completed");
}
}
here
t1.start();
t2.start();
System.out.println("completed");
here
in this t1.start() and t2.start() are written in sequential order, so my doubt is that both the thread starts at the same or not
or t1 starts, executes then comes to t2 and executes, if this is correct, how this becomes a deadlock situation..i want to know the execution of these threads

When you launch your java program, JRE spawns main thread and that main thread executes your main method.
When you call t1.start(), new thread spawns and executes first anonymous class's run method. From this point there are 2 threads executing simultaneously in your program: "main thread" and "thread 1".
When you call t2.start(), another thread spawns and executes second anonymous class's run method. From this point there are 3 threads executing simultaneously in your program: "main thread", "thread 1", "thread 2".
The order in which threads are executing is not defined. It could be anything. Generally they are executing simultaneously.
Your "thread 1" and "thread 2" acquire locks on resource1 and resource2 correspondingly and sleep for 10 seconds. While that happens, your "main" thread finishes its execution. But there are 2 more threads in your program, so while main method finished, program is not finished yet.
After sleeping your "thread 1" and "thread 2" trying to acquire locks on resource 2 and resource 1, but those locks are already acquired so they will wait until lock holder will release it. Lock holder will never release it, as it waits for other resource so this program will never stop. That's classic deadlock situation.

I have learned that to prevent deadlocks, you need to make the synchronized block be consistently the same.
public void run() {
synchronized (resource1) {
synchronized (resource2) {
System.out.println("Thread 1: locked resource 1");
System.out.println("Thread 1: locked resource 2");
try { Thread.sleep(10000);} catch (Exception e) {}
}
}
}
and
Thread t2 = new Thread() {
public void run() {
synchronized (resource1) {
synchronized (resource2) {
System.out.println("Thread 2: locked resource 2");
System.out.println("Thread 2: locked resource 1");
try { Thread.sleep(10000);} catch (Exception e) {}
}
}
}
};

in this t1.start() and t2.start() are written in sequential order, so
my doubt is that both the thread starts at the same or not or t1
starts, executes then comes to t2 and executes
A call to start() doesn't ensure that a Thread starts immediately. A native call is made via start0() which inturn calls the OS to fork a thread. So, basically, thread2 can start before thread1. You have no control over which thread starts first.
how this becomes a deadlock situation
There is a probability of deadlock here because t1 might get lock on resource1 and t2 might get lock on resource2 at the same time. Now, both threads want the resource held by the other thread. Hence you have a deadlock.
So as a standard practice, both t1 and t2 should acquire lock in the same sequence.

sleep() guarantees that both t1 and t2 acquire their first lock before they proceed to their second lock. No matter which thread runs first.

"so my doubt is that both the thread starts at the same or not or t1 starts, executes then comes to t2 and executes"
Simply because the threads t1 and t2 are spawned sequentially, does not imply that they execute sequentially. Threads are used for parallel execution of units of work.
Due to the sleep method calls in your code, it will deadlock because
t1 acquires R1 or t2 acquires t2. The order is indeterminate
Both threads sleep for 10 seconds after acquiring their respective resource, so we can be say with high degree of certainty in this example that both threads have acquired the resources at some point during the sleep period of the other.
When t1 or t2 wake up and try to acquire the second resource, which is already held by the respective threads sibling it will block. Both threads will block attempting to acquire the resource held by the other.
This scenario only occurs because the threads are executing in parallel, not sequentially.
Please see http://docs.oracle.com/javase/tutorial/essential/concurrency/deadlock.html

The order of thread execution is not defined.
There is a high risk for your program to go to deadlock. But you can slightly change the order of lock in the second thread to avoid deadlock. I've modified and given below. Again this depends on the logic you are going to write.
Thread t2 = new Thread() {
public void run() {
synchronized (resource1) {
System.out.println("Thread 2: locked resource 2");
try { Thread.sleep(10000);} catch (Exception e) {}
System.out.println("Thread 2: Waiting for resource 1...");
synchronized (resource2) {
System.out.println("Thread 2: locked resource 1 and 2");
}
}
}
};

Related

Java Condition.await() is not signaled until its lock calls unlock() [duplicate]

This question already has an answer here:
Why await of Condition releases the lock but signal does not?
(1 answer)
Closed 8 months ago.
Java doc for Condition.await():
The lock associated with this Condition is atomically released and the
current thread becomes disabled for thread scheduling purposes and
lies dormant until one of four things happens:
Some other thread invokes the signal method for this Condition
...
I wrote a test program to see, after Thread-1 calls Condition.await() and gets blocked, Thread-2 calls Condition.signal().
I expect Thread-1 should return immediately from await() and continue.
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.*;
public class TestThreadCondition {
public static void main(String[] args) throws InterruptedException {
Lock rLock = new ReentrantLock();
Condition cond = rLock.newCondition();
AtomicBoolean aBool = new AtomicBoolean(true);
Thread t1 = new Thread(new Runnable() {
#Override public void run() {
try {
rLock.lock();
System.out.println("(Step 1) Thread 1 locks and sleeps 1s");
Thread.sleep(1000);
while (aBool.get()) {
System.out.println("(Step 3) Thread 1 enters while loop");
cond.await();
System.out.println("(Step 5) Thread 1 got signal");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
rLock.unlock();
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
#Override public void run() {
try {
Thread.sleep(300);
System.out.println("(Step 2) Thread 2 also requires lock, blocked");
rLock.lock();
System.out.println("(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal");
cond.signal(); // I hope this would signal "t1" and t1 will enter (Step 5) immediately.
System.out.println("(Step 6) Thread 2 sleeps 3s and set aBool");
Thread.sleep(3000);
aBool.compareAndSet(true, false);
} catch (Exception e) {
e.printStackTrace();
} finally {
rLock.unlock();
System.out.println("(Step 7) unlock");
}
}
});
t2.start();
t1.join();
t2.join();
}
}
I expected that this program will run and print
Step1->Step2->Step3->Step4->Step5->Step6->Step7.
But the actual result was:
(Step 1) Thread 1 locks and sleeps 1s
(Step 2) Thread 2 also requires lock, blocked
(Step 3) Thread 1 enters while loop
(Step 4) Thread 2 gets lock after thread 1 cond wait, sends signal
(Step 6) Thread 2 sleeps 3s and set aBool
(Step 7) unlock
(Step 5) Thread 1 got signal
The Step 5 was executed after Step6 and Step7. It looks like that in Thread-1, cond.await() was not awaken when Thread-2 called cond.signal, and it blocks until Thread-2 called rLock.unlock().
This seems conflicts with the Javadoc's explanation, as I stated at the beginning. How to understand the behavior of my code?
At the time your code prints
(Step 5) Thread 1 got signal
Thread1 has already exited the await method. It cannot have gotten that far without already having acquired the lock. So naturally that can't happen if another thread still has the lock.
So your code isn't a good test, we don't know from it whether the signal was delayed until the lock was released, or if the signal occurred earlier than that and thread1 was woken up but was blocking on getting the lock.
In the comparable situation with intrinsic locks it is spelled out in the apidoc that notify is delayed until the notifying thread releases its lock. The waiting thread can't act until then anyway. If that same situation occurs here that would not be surprising.
There isn't a contradiction in the javadoc in any case, waking up and acquiring the lock are two different things.

Thread deadlock avoidance

I want to know if it's authorized to avoid Thread deadlocks by making the threads not starting at the same time? Is there an other way to avoid the deadlocks in the following code?
Thanks in advance!
public class ThreadDeadlocks {
public static Object Lock1 = new Object();
public static Object Lock2 = new Object();
public static void main(String args[]) {
ThreadDemo1 t1 = new ThreadDemo1();
ThreadDemo2 t2 = new ThreadDemo2();
t1.start();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
t2.start();
}
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}
}
There are two ways to get a deadlock:
Lock escalation. For example, a thread holding a shareable read
lock tries to escalate to an exclusive write lock. If more than one
thread holding a read lock tries to escalate to a write lock, a
deadlock results. This doesn't apply to what you're doing. (Offhand, I don't even know if it's possible to escalate a lock in Java.)
Unspecified lock order. If thread A locks object 1, then tries to lock object 2, while thread B locks object 2 then tries to lock object 1, a deadlock can result. This is exactly what you're doing.
Those are the only ways to get a deadlock. Every deadlock scenario will come down to one of those.
If you don't want deadlocks, don't do either of those. Never escalate a lock, and always specify lock order.
Those are the only ways to prevent deadlocks. Monkeying around with thread timing by delaying things is not guaranteed to work.
As the other mentioned, delays won't help because threads by their nature have unknown start time. When you call start() on a thread, it becomes runnable, but you cannot know when it will be running.
I'm assuming this is just demo code, so you already know that playing with sleeps is not guaranteed to work (as stressed in other answers).
In your demo code I see two options to try avoid the deadlock:
Remove any sleep within the body of the functions executed by the threads and just put a single, long enough, sleep between the start of the two threads; in practical terms, this should give enough time to the first thread to be scheduled and complete its work, then the second thread will acquire both locks without contention. But, you already know, scheduling policies are not under your control and this is not guaranteed to work at all.
Do acquire locks in the same order in both threads, without using any sleep at all, i.e.
synchronized (Lock1) {
synchronized (Lock2) {
// ...
}
}
This is guaranteed to remove any possible deadlock, because the first thread to acquire Lock1 will gain the possibility to complete its work while blocking the other thread until completion.
UPDATE:
To understand why acquiring locks in the same order is the only guaranteed way to avoid deadlock, you should recall what's the whole purpose of locks.
A thread is said to own a lock between the time it has acquired the lock and released the lock. As long as a thread owns a lock, no other thread can acquire the same lock. In fact, the other thread will block when it attempts to acquire the same lock.
Every object in Java has an intrinsic lock associated with it. The synchronized statement let you automatically acquire the intrinsic lock of the specified object and release it after code execution.
No, starting threads at different times is not a way to avoid deadlocks - in fact, what you'd be trying with different start times is a heuristic to serialize their critical sections. ++ see why at the and of this answer
[Edited with a solution]
Is there an other way to avoid the deadlocks in the following code?
The simplest way is to acquire the locks in the same order on both threads
synchronized(Lock1) {
// do some work
synchronized(Lock2) {
// do some other work and commit (make changes visible)
}
}
If the logic of your code dictates you can't do that, then use java.util.concurrent.locks classes. For example
ReentrantLock Lock1=new ReentrantLock();
ReentrantLock Lock2=new ReentrantLock();
private static class ThreadDemo1 extends Thread {
public void run() {
while(true) {
Lock1.lock(); // will block until available
System.out.println("Thread 1: Holding lock 1...");
try {
// Do some preliminary work here, but do not "commit" yet
Thread.sleep(10);
} catch (InterruptedException e) {
}
System.out.println("Thread 1: Waiting for lock 2...");
if(!Lock2.tryLock(30, TimeUnit.MILLISECOND)) {
System.out.println("Thread 1: not getting a hold on lock 2...");
// altruistic behaviour: if I can't do it, let others
// do their work with Lock1, I'll try later
System.out.println("Thread 1: release lock 1 and wait a bit");
Lock1.unlock();
Thread.sleep(30);
System.out.println("Thread 1: Discarding the work done before, will retry getting lock 1");
}
else {
System.out.println("Thread 1: got a hold on lock 2...");
break;
}
}
// if we got here, we know we are holding both locks
System.out.println("Thread 1: both locks available, complete the work");
// work...
Lock2.unlock(); // release the locks in the reverse...
Lock1.unlock(); // ... order of acquisition
}
}
// do the same for the second thread
++ To demonstrate why delays in starting the threads at different times is not a foolproof solution, think if you can afford to delay one of the threads by 10 seconds in the example below. Then think what will you do if you don't actually know how long to wait.
private static class ThreadDemo1 extends Thread {
public void run() {
synchronized (Lock1) {
System.out.println("Thread 1: Holding lock 1...");
try {
// modelling a workload here:
// can take anywhere up to 10 seconds
Thread.sleep((long)(Math.random()*10000));
} catch (InterruptedException e) {
}
System.out.println("Thread 1: Waiting for lock 2...");
synchronized (Lock2) {
System.out.println("Thread 1: Holding lock 1 & 2...");
}
}
}
}
private static class ThreadDemo2 extends Thread {
public void run() {
synchronized (Lock2) {
System.out.println("Thread 2: Holding lock 2...");
try {
// modelling a workload here:
// can take anywhere up to 10 seconds
Thread.sleep((long)(Math.random()*10000));
} catch (InterruptedException e) {
}
System.out.println("Thread 2: Waiting for lock 1...");
synchronized (Lock1) {
System.out.println("Thread 2: Holding lock 1 & 2...");
}
}
}
}

Why the below program, without a sleep go to deadlock state but with sleep it executes all the three threads and terminates normally?

public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
ExampleTest obj = new ExampleTest();
Thread t1 = new Thread(new Runn(obj));
Thread t2 = new Thread(new Runn(obj));
Thread t3 = new Thread(new Runn(obj));
t1.start();
t2.start();
t3.start();
//Thread.sleep(1);
obj.exit();
}
}
class ExampleTest {
public synchronized void enter() {
try {
System.out.println("printed " +Thread.currentThread().getName() +" inside wait");
this.wait();
System.out.println("printed " +Thread.currentThread().getName() +" exit wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("printed " +Thread.currentThread().getName() +" at time: "+System.currentTimeMillis());
}
public synchronized void exit() {
this.notifyAll();
}
}
class Runn implements Runnable {
ExampleTest obj;
public Runn(ExampleTest obj) {
this.obj = obj;
}
#Override
public void run() {
obj.enter();
}
}
what is the role of notifyAll(). Will notifyAll() allows all the waiting thread to acquire lock sequentially in random order or only one thread can acquire the lock?
Without the sleep statement the statement obj.exit(); will be very likely be executed before all of your threads reaching their wait status. ie. the notifyAll call will be over before at least one of your thread is in wait status. So at least one of your threads will be stuck in wait status waiting for some other thread to notify it and wake up. But that will never happen as obj.exit() is already finished.
With your sleep statement in place , all of your threads will get a chance to reach their wait status and your notifyAll call after the sleep will wake them all, The order of waking up will not be deterministic and will be handled by the thread scheduler.
Your code suffers from the "lost notification" syndrome, which is alleviated (but not deterministically avoided) by the sleep call.
You haven't provided any mechanism which would ensure that, at the time of calling exit, all the threads have already reached their wait call. Therefore some threads will miss the notification and enter an eternal wait state.
The notifyAll call does wake up all waiting threads, but it doesn't wake up threads which enter the wait state in the future.
With the following code:
t1.start();
t2.start();
t3.start();
You are starting the threads. Starting threads might take some time as it involves memory allocation and other operations. When your threads run they enter a wait state. Started threads do not, however, execute immediately. They start executing as soon as the scheduler decides it is time for them to execute. When you call start the main thread is currently running on the CPU. Without the sleep most likely the main thread will keep the CPU and call:
obj.exit();
Before the threads actually started, that is, before the threads actually entered the wait state. The notifyAll will execute in vain, as threads are not started yet and therefore are not waiting. The notification will be lost.
With the sleep call you are suspending the main thread for quite some time (for the CPU perspective). This means that the other threads will most likely get the CPU and enter the wait state. So when you then call notifyAll this time the notification will not get lost. Notice that there is no guarantee that this will happens: it might still happen that when you call exit() some (or all) other threads have not yet executed their wait.

Why await of Condition releases the lock but signal does not?

I write the below code to test when will the thread is awake when it is waiting for a Condition object.
But I find I have to unlock after I call signal(). Lock is not release by this method, while await() will release this lock .
This is from Condition#await
The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant until one of four things happens:
And this is from Conditon#signal
Wakes up one waiting thread.
If any threads are waiting on this condition then one is selected for waking up. That thread must then re-acquire the lock before
returning from await.
But in my code, this is not true, until we unlock the lock. Why it is design like this? Since in my opinion, when we decide to to signal the others, we should not hold the lock any more,am I wrong?
Since we can do many things between calling signal and unlock ,say I sleep 10 seconds, what exactly the time java signal the other thread? Is there a another background thread who is working between we signal and unlock?
public class WorkerThread extends Thread{
#Override
public void run() {
Monitor.lock.lock();
while (!Monitor.isConditionTrue){
try {
Monitor.condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("THREAD ID "+this.getId()+"-------working --------");
System.out.println("------singnall--------");
Monitor.isConditionTrue=true;
Monitor.condition.signal();
try {
Thread.sleep(3000);//here, the thread is sleeping while another thread is not awaken since the lock is not releases
System.out.println("------unlock--------");
Monitor.lock.unlock();//now the other thread is awaken, if I do not explicitly unlock , no thread will be awaken.
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Monitor {
static ReentrantLock lock = new ReentrantLock();
static Condition condition = lock.newCondition();
static volatile boolean isConditionTrue = true;
public static void main(String args[]) {
Thread t1 = new WorkerThread();
Thread t2 = new WorkerThread();
t1.start();
t2.start();
Thread.sleep(2000);
lock.lock();
isConditionTrue=true;
condition.signalAll();
lock.unlock();
}
}
OUTPUT:
THREAD ID 9-------working --------
------singnall--------
------unlock--------
THREAD ID 10-------working --------
------singnall--------
------unlock--------
You have missed this sentence in Contition#await:
In all cases, before this method can return the current thread must re-acquire the lock associated with this condition. When the thread returns it is guaranteed to hold this lock.
In other words, you must explicitly release the lock after await, just as with signal.
Why this mechanism is sound: if you first released the lock, then signaled, you'd be open to race conditions where other threads made changes between releasing the lock and the signal reaching a parked thread. The way the mechanism works, first a definite thread is chosen to be awoken by the signal, then it waits for the lock, then the signaling thread releases it, then the awoken thread goes on.
You might argue that signal could do all of this internally, but then:
the API would become confusing: there would be more than one method releasing the lock;
the APi would become more restrictive and preclude any use cases where the thread wants to do something more before releasing the lock, such as atomically issuing more signals.

Does synchronized park a concurrent thread like Lock.lock() does?

When we call either lock.lock() or try to enter a synchronized block then our thread blocks if some other thread has already taken that lock. Now my question is, when we look at the implementation of lock.lock() it delegates acquiring lock to AQS which actually parks the current thread (so that it cannot be scheduled further by scheduler).
Is it the same case with synchronized blocking also?
I even think my thread status are also different. For example, if my thread is blocked on synchronized block it will be BLOCKING while if I have called
lock.lock(), then it will be WAITING. Am I right?
My Concern is the difference between the below two locking strategies in aspects of Thread.status and performance improvement by parking instead of busy waiting
ReentrantLock.lock();
synchronize { /*some code */ }
BLOCKING - is blocked on a resource, cannot be interrupted
WAITING - is blocked on a resource, but can be interrupted or notified or unparked.
As you can see WAITING is better for control from another processed. e.g. if two threads are deadlocked you could break a lock() with an interrupt. With a two thread using synchronized you are stuck.
The behaviour of the synchronized vs lock is very similar and the exact details change between major revisions.
My advise is to use
synchronized for simpler code where you need thread safety but have a very low lock contention.
use Lock where you have identified you have lock contention, or you need additional functionality like tryLock.
If you do
final Lock lock = new ReentrantLock();
lock.lock();
Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
Thread.sleep(100);
System.out.println(t + " is " + t.getState());
lock.unlock();
prints
Thread[Thread-0,5,main] is WAITING
Thread.State states
Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:
Object.wait with no timeout
Thread.join with no timeout
LockSupport.park
A thread in the waiting state is waiting for another thread to perform a particular action. For example, a thread that has called Object.wait() on an object is waiting for another thread to call Object.notify() or Object.notifyAll() on that object. A thread that has called Thread.join() is waiting for a specified thread to terminate.
Calling upon lock or lockInterruptibly will put the thread in WAITING state:
Thread state for a waiting thread. A thread is in the waiting state due to calling one of the following methods:
Object.wait with no timeout
Thread.join with no timeout
LockSupport.park
The following code starts four threads, first two (A,B) run the same code and lock some monitor via the lock method. The other two (C,D) also run the same code, but they lock some another monitor via the lockInterruptibly method:
public static synchronized void dumpThreadState(List<Thread> threads) {
System.out.println("thread state dump start");
for (Thread t: threads) {
System.out.println(t.getName()+" "+t.getState());
}
System.out.println("thread state dump end\n");
}
public static void main(String[] args) throws InterruptedException {
final Lock lock = new ReentrantLock();
final Lock anotherLock = new ReentrantLock();
List<Thread> threads = new LinkedList<Thread>();
Runnable first = new Runnable() {
#Override
public void run() {
try {
lock.lock();
}
catch (Exception ex) {
System.out.println(Thread.currentThread().getName()+" processing exception "+ex.getClass().getSimpleName());
}
while (true);
}
} ;
Runnable second = new Runnable() {
#Override
public void run() {
try {
anotherLock.lockInterruptibly();
}
catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName()+" was interrupted");
}
while (true);
}
};
threads.add(new Thread(first,"A"));
threads.add(new Thread(first,"B"));
threads.add(new Thread(second,"C"));
threads.add(new Thread(second,"D"));
dumpThreadState(threads);
for (Thread t: threads) {
t.start();
}
Thread.currentThread().sleep(100);
dumpThreadState(threads);
System.out.println("interrupting " + threads.get(1).getName());
threads.get(1).interrupt();
dumpThreadState(threads);
System.out.println("interrupting " + threads.get(3).getName());
threads.get(3).interrupt();
Thread.currentThread().sleep(100);
dumpThreadState(threads);
for (Thread t: threads) {
t.join();
}
}
It outputs:
thread state dump start
A NEW
B NEW
C NEW
D NEW
thread state dump end
thread state dump start
A RUNNABLE
B WAITING
C RUNNABLE
D WAITING
thread state dump end
interrupting B
thread state dump start
A RUNNABLE
B WAITING
C RUNNABLE
D WAITING
thread state dump end
interrupting D
D was interrupted
thread state dump start
A RUNNABLE
B WAITING
C RUNNABLE
D RUNNABLE
thread state dump end
As it can be seen the thread locked via the lock method can not be interrupted, while thread locked with lockInterruptibly can.
In the other example three threads are started, the first two (A,B) run the same code and lock upon the same monitor via the synchronized block. The third thread locks on another monitor but waits via the wait method:
public static void main(String[] args) throws InterruptedException {
final Object lock = new Object();
final Object anotherLock = new Object();
List<Thread> threads = new LinkedList<Thread>();
Runnable first = new Runnable() {
#Override
public void run() {
synchronized(lock) {
while (true);
}
}
} ;
Runnable second = new Runnable() {
#Override
public void run() {
synchronized(anotherLock) {
try {
anotherLock.wait();
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
};
threads.add(new Thread(first,"A"));
threads.add(new Thread(first,"B"));
threads.add(new Thread(second,"C"));
dumpThreadState(threads);
for (Thread t: threads) {
t.start();
}
Thread.currentThread().sleep(100);
dumpThreadState(threads);
for (Thread t: threads) {
t.join();
}
}
It outputs:
thread state dump start
A NEW
B NEW
C NEW
thread state dump end
thread state dump start
A RUNNABLE
B BLOCKED
C WAITING
thread state dump end
Thread C ended up in WAITING state while thread B ended up in BLOCKING state:
Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling Object.wait.
EDIT:
Here is a real nice UML diagram of thread states.
Parking a thread and synchronized blocking are very different. When you try and enter a synchronized block, you are explicitly attempting to acquire a monitor on an object instance. If you can not acquire the monitor, your thread will go into the BLOCKING state until the monitor is available. Parking is more similar to the Object.wait() method in that the code knows that it can't continue until some other condition becomes true. There's no sense in blocking here because it would be fruitless because my condition for continuing on is currently true. At this point I go into the WAITING or TIMED_WAITING (depends on how the wait is issued) state until I am notified (via something like notify(), notifyAll() or unpark()). Once my condition becomes true I come out if my wait state and then probably attempt to acquire monitors and go into BLOCKING if I need them. If I get my monitors, I go into RUNNING and continue on my merry way
So waiting is really about knowing that I can't do something and having some other thread notify me when it thinks I can. It can lead to blocking after I wake up though. Blocking is just competing for access to a monitor without an explicit other prerequisite condition.
When lock() is called on a Lock instance, the calling thread is actually put into a wait state and is not blocking. The benefit here is that this wait state can be interrupted and this helps to avoid deadlocks. With something like the Lock class, you have a bunch of options on desired waiting behaviors via tryLock(), tryLock(long,TimeUnit), lock() and lockInterruptibly(). You can specify things like how long you want to wait and if you can be interrupted via which method you call. With synchronized code, you don't have such options. You're blocking and you're stuck blocking until some thread gives up the monitor you want and if it never does, you are deadlocked. That's why since Java 5 and the concurrent package, you should avoid using the synchronized keyword and instead try and implement similar semantics with things like Lock and Condition.

Categories

Resources