I am new to using threads in java . I have a simple reader writer problem where that when a writer comes in on a thread, a reader will wait for the writer to complete.
However, when I run my program, I find that my thread doesn't get notified? Why is this?
My code is below:
public class ReaderWriter {
Object o = new Object();
volatile boolean writing;
Thread readerThread = new Thread( "reader") {
public void run() {
while(true) {
System.out.println("reader starts");
if(writing) {
synchronized (o) {
try {
o.wait();
System.out.println("Awaked from wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println( "reader thread working "+o.hashCode());
}
}
};
Thread writerThread = new Thread("writer" ) {
public void run() {
System.out.println( " writer thread");
try {
synchronized (o) {
writing = true;
System.out.println("writer is working .. ");
Thread.sleep(10000);
writing = false;
o.notify();
System.out.println("reader is notified");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
public static void main(String[] args) {
ReaderWriter rw=new ReaderWriter();
rw.readerThread.start();
rw.writerThread.start();
}
}
Here the problem is with the synchronized (o) function.
The synchronized function makes the thread synchronized and there by
it only execute only one thread at a time to the object o. Hence
while the value of writing is true. It wont allow the 2nd tread
readerThread to execute the due to the synchronized (o) in the readerThread
You are getting an Infinite loop because there is no terminate statement.
Look here to know when thread terminates
Look at this code to Know more about synchronized function
synchronized(object) {
// statements to be synchronized
}
Here, object is a reference to the object being synchronized. A
synchronized block ensures that a call to a method that is a member of
object occurs only after the current thread has successfully entered
object's monitor
.
Read this to check about the notify methods
The Object class in JavaSW has three final methods that allow threads to communicate about the locked status of a resource. These methods are wait(), notify(), and notifyAll(). A thread obtains a lock for a particular resource via a synchronized block with an instance of that resource. Suppose that a thread requires that another thread perform a certain action on the resource before it acts on the resource. That thread can synchronize on the resource and call the wait() method on resource. This says that the thread will wait until it has been notified that it can proceed to act.
The wait() method can take an optional timeout value as a parameter.
If this value is used, it means that the thread will either wait until
it's notified or it will continue to execute once the timeout value
has passed.
If a thread is required to perform a task on a resource before another thread operates on the resource (and the other thread is waiting via the wait() method on the resource), the thread needs synchronize on the resource. It can perform its actions on the resource.
In order to notify the waiting thread once these actions have completed, the notify() method on the resource is called. This notifies the waiting thread that it can proceed to act. If multiple threads are waiting for the resource, there is no guarantee as to which thread will be given access to the resource. If it is desired for all waiting threads to be awoken, the notifyAll() method can be called on the resource.
The problem is that writing is set to false prior notification.
Thread.sleep() alone does not wake up other waiting threads.
The writer thread is always holding the lock on your monitor object while writing is set to true. This is why the synchronized block in your reader thread will never be entered while writing is set to true.
synchronized (o) { // Thread aquires lock on monitor o. writing is false.
writing = true; // writing is true, lock still held.
System.out.println("Writer is working...");
Thread.sleep(1000); // Thread sleeps while holding lock.
writing = false; // writing is changed back to false, lock still held.
o.notify();
System.out.println("Reader is notified");
} // Here lock is released, writing is false.
That is writing is set to false before aquiring the lock and it is false when releasing the lock. While the lock is held this synchronized block in the reader thread will not be entered:
while (true) {
if (writing) {
synchronized (o) { // Lock always held by writer when writing=true.
try {
o.wait();
System.out.println("Awaked from wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
thanks for your cooperation and valuable suggestions, I make a bit change in my code
public class ReaderWriter {
Object o = new Object();
volatile boolean writing;
Thread readerThread = new Thread( "reader") {
public void run() {
System.out.println("reader starts");
synchronized (o) {
System.out.println("reader aquire the lock");
while(writing) {
try {
System.out.println("Reader goes to wait ....");
o.wait();
System.out.println("Awaked from wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while(!writing) {
//do something
System.out.println("hiiiiiiii");
}
System.out.println("reader release the lock");
}
}
};
Thread writerThread = new Thread("writer" ) {
public void run() {
System.out.println( "writer starts");
try {
writing = true;
synchronized (o) {
System.out.println("writer aquire the lock");
Thread.sleep(10000);
o.notify();
System.out.println("reader is notified");
System.out.println("writer release the lock");
}
writing = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
public static void main(String[] args) {
ReaderWriter rw=new ReaderWriter();
rw.readerThread.start();
rw.writerThread.start();
}
}
Now I found a thing very interesting that "Awaits from wait" only when reader acquire the lock first and after the correction I put writing = true and writing = false outside the syncronized block so that after acquiring the lock by the reader when writer comes it changes the writing flag and thus reader goes to wait and release the lock for writer, writer acquire the lock do Thread.sleep and notify the reader and hence release the lock for reader. Reader awakes and find that the writing flag is set to false by writer, so reader starts performing its operation.
There can be only two cases when writer thread first enters its critical section or when reader thread enters first since by no means you are stopping one to sleep for other to start first.
1) In first case when writer thread enters critical section first synchronized block locks the object o and after waking up from sleep you notify but you are not releasing lock explicitly till sync block ends which unlocks the object automatically .So even if notification is sent inside block reader thread wont be able to take the lock .So after syn block of your writer thread is over you reader thread would run uninterrupted assuming there is no interrupt from third thread .
2) In second case when you reader thread is scheduled by scheduler to run first it will obtain a lock and on finding flag false it will enter infinite loop of printing hi on output console and its is infinite since you have take lock of object and entered infinite loop which makes writer thread wait indefinitely on reader thread
Correcting your code as below for reader thread
synchronized (o) {
System.out.println("reader aquire the lock");
if(writing) {
try {
System.out.println("Reader goes to wait ....");
System.out.println("Awaked from wait");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
else{
//do something
o.notify();
o.wait(); // in this case only reader release the lock would only be printed and if block wont be executed
}
System.out.printn("reader release the lock");
}
Related
I am trying to understand interruptible locks in Java.
I came across code which involved interruptible lock:
public class ReenterantLockInterruptbly {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread thread = new Thread(() -> {
int i = 0;
System.out.println("before entering ReentrankLock block");
try {
lock.lockInterruptibly();
while (0 < 1) {
System.out.println("in the ReentrankLock block counting: " + i++);
}
} catch (InterruptedException e) {
System.out.println("ReentrankLock block interrupted");
}
});
lock.lock(); // lock first to make the lock in the thread "waiting" and then interruptible
thread.start();
thread.interrupt();
}
}
This printed:
before entering ReentrankLock block
ReentrankLock block interrupted
The program then terminated.
I feel I understand the reason for the output.
Next I decided to replace interruptible lock with uninterruptible/normal lock:
public class ReenterantLockInterruptbly {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread thread = new Thread(() -> {
int i = 0;
System.out.println("before entering ReentrankLock block");
try {
lock.lock();
while (0 < 1) {
System.out.println("in the ReentrankLock block counting: " + i++);
}
} catch (Exception e) {
System.out.println("ReentrankLock block interrupted");
}
});
lock.lock(); // lock first to make the lock in the thread "waiting" and then interruptible
thread.start();
thread.interrupt();
System.out.println("Main thread called thread.interrupt()");
}
}
It printed:
Main thread called thread.interrupt()
before entering ReentrankLock block
The program then did not terminate. I did not understand why?
Q1. Is it because new / child thread is not able obtain lock which was not released by main thread, neither it is holding interruptible lock in order for it to get interrupted out of lock() as requested by main thread?
Q2. So child thread is stuck in wait set of lock, whereas main thread is executed to completion and terminated. Is it so?
Q3. If answer to 2 is yes, shouldnt completion and termination of main thread also terminate child thread too?
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...");
}
}
}
}
I was just curious is it possible that a thread T1 say executes a synchronization block partially and then releases the lock on the object and another thread T2 executes the same block? Something like this:
line1: synchronized(this){
line2: if(INSTANCE == null)
line3: INSTANCE = new Object(); //say a variable is initialized
line4: return INSTANCE;
line5: }
Is it possible that thread T1 acquires a lock on current object (this) and executes line1 and line2. Then thread T1 is preempted by thread T2, T1 releases lock and T2 acquires lock on this and executes the same block (all the lines1 to 5). Then thread T1 again takes the lock and continues executing from line3?
Basically, T1 will see INSTANCE as null and so will T2 and each will create a new Object.
If this is not possible can someone explain why not?
Addendum:
Thanks everyone for your answer. My question was a bit misleading. What I am exactly asking, is it possible that once a thread is executing a synchronized block it can release the lock before the entire block is executed (not by explicitly calling wait() but something which is process, CPU dependent)? Is there a contract in JLS or a JVM guarantee that once a thread starts executing a synchronized block the lock on the object is not released until the end of the block? My understanding is synchronization guarantees no 2 threads can simultaneously execute the block (or other synchronized method/block) but the lock is hold until the end of the block is reached? It's kind of obvious but is it specified in the JLS?
Thread preemption doesn't cause the preempted thread to release its locks. If it did, locks would be worthless. The whole point of a synchronized block is that it will disallow other threads from synchronizing on the same object until the thread releases the lock (by leaving the synchronized block).
Even if a thread is preempted, it won't release a lock. The lock is still held. If another thread comes along, it will block (stop running) until the lock is released, even if the original thread gets preempted several times before it releases the lock. Basically almost any kind of lock has some storage in the heap that gets written to indicate there's a lock. It's permanent until the thread or the system writes a different value to indicate the lock is free.
It is of course possible to write code that allows access to an instance or field without ever taking the lock, but that's a coding error. It's also possible for the original thread to exit the block early (say it throws an exception) -- this releases the lock, and other threads can continue as normal.
I'm pretty sure it's not possible for a second thread to enter the synchronize block before the first one has executed the entire block. On obtaining the lock on the object, all other threads attempting to enter the synchronized code will be blocked.
See more information here: http://tutorials.jenkov.com/java-concurrency/synchronized.html
Basically you can use Locks objects. Lock objects can allow you to sequentially apply and release locks on multiple locks line by line.
A very good tutorial on how to implement it here
Check out below code:
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class test2{
private static Object instance = null;
private static test2 t = new test2();
private static Lock lock = new ReentrantLock();
public static void main(String[] args) {
A a = new A();
B b = new B();
a.setName("Thread-A");
b.setName("Thread-B");
a.start();
b.start();
}
public Object getObj(){
try {
lock.lock();
System.out.println("Begin Current thread: "+ Thread.currentThread().getName());
if(instance == null){
if(Thread.currentThread().getName().equalsIgnoreCase("Thread-A")){
lock.unlock();
while(instance==null){
System.out.println(Thread.currentThread().getName() +" : instance is null");
}
while(true){
if(!lock.tryLock()){
System.out.println(Thread.currentThread().getName() + " waiting for re lock");
}else{
lock.lock();
break;
}
}
}
instance =new Object();
System.out.println("End Current thread: "+ Thread.currentThread().getName());
if (((ReentrantLock) lock).isHeldByCurrentThread()) {
lock.unlock();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return instance;
}
public static class A extends Thread{
#Override
public void run() {
while(true){
if(t.getObj() != null){
break;
}
}
}
}
public static class B extends Thread{
#Override
public void run() {
while(true){
if(t.getObj() != null){
break;
}
}
}
}
}
Output
Begin Current thread: Thread-A
Thread-A : instance is null
Begin Current thread: Thread-B
Thread-A : instance is null
End Current thread: Thread-B
Thread-A waiting for re lock
End Current thread: Thread-A
I research ReentrantReadWriteLock
snippet from java doc:
The thread will not acquire the read lock until after the oldest
currently waiting writer thread has acquired and released the write
lock
Thus As I understood.
read duration- 1 time unit
write duration- 3 time unit
time 0 - write lock acquired
time 1 - read lock try read
time 2 -
write lock try write
Thus I expect following sequence:
first write
second write
read
my experiment code:
public class RWLockCalculator {
static long initTime = System.currentTimeMillis();
private static int calculatedValue = 0;
private static ReadWriteLock lock = new ReentrantReadWriteLock();
public void calculate(int value) {
lock.writeLock().lock();
try {
System.out.println("write lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
this.calculatedValue = 1;
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
public int getCalculatedValue() {
lock.readLock().lock();
try {
System.out.println("read lock acquired at "+ (System.currentTimeMillis()-RWLockCalculator.initTime));
Thread.sleep(100);
return calculatedValue;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return -1;
} finally {
lock.readLock().unlock();
}
}
}
class Test {
public static void main(String[] args) throws InterruptedException {
new WriteThread().start();
Thread.sleep(100);
new ReadThread().start();
Thread.sleep(100);
new WriteThread().start();
}
}
class ReadThread extends Thread {
#Override
public void run() {
System.out.println(new RWLockCalculator().getCalculatedValue() + ", " + (System.currentTimeMillis() - RWLockCalculator.initTime));
}
}
class WriteThread extends Thread {
#Override
public void run() {
new RWLockCalculator().calculate(99);
System.out.println("I have written in " + (System.currentTimeMillis() - RWLockCalculator.initTime));
}
}
out:
write lock acquired at 0
I have written in 300
read lock acquired at 300
1, 400
write lock acquired at 400
I have written in 700
Thus I get
first write
read
second write
Why do I get this result?
Is it possible to break FIFO ordering?
Update
Please compare two sibling snippets from java doc(about fair mode):
first
A thread that tries to acquire a fair read lock (non-reentrantly) will block if either the write lock is held, or there is a waiting writer thread. The thread will not acquire the read lock until after the oldest currently waiting writer thread has acquired and released the write lock. Of course, if a waiting writer abandons its wait, leaving one or more reader threads as the longest waiters in the queue with the write lock free, then those readers will be assigned the read lock.
second:
A thread that tries to acquire a fair write lock (non-reentrantly) will block unless both the read lock and write lock are free (which implies there are no waiting threads). (Note that the non-blocking ReentrantReadWriteLock.ReadLock.tryLock() and ReentrantReadWriteLock.WriteLock.tryLock() methods do not honor this fair setting and will acquire the lock if it is possible, regardless of waiting threads.)
I do not fully understand the meaning of what is written there But I see that ReentrantReadWriteLock uses different politics for acquire read lock and write lock. I suggest that if politics were same in java doc wouldn't write two indents.
ReadLock can share locks. Is it only one difference?
First of all, ReentrantReadWriteLock should be created in fair mode to impose particular order of lock acquisition:
private static ReadWriteLock lock = new ReentrantReadWriteLock(true);
Then, javadoc describes you case pretty clearly:
When constructed as fair, threads contend for entry using an approximately arrival-order policy. When the currently held lock is released either the longest-waiting single writer thread will be assigned the write lock, or if there is a group of reader threads waiting longer than all waiting writer threads, that group will be assigned the read lock.
Since your reader thread waited longer than the second writer thread, it acquires a lock before the writer thread.
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.