I was trying to understand more about Thread.interrupt(), and so I wrote the following codes.
public class Test {
private Object object = new Object();
Runnable thread1 = () -> {
synchronized (object) {
System.out.println(System.currentTimeMillis() + " - Thread1 inside synchronized block");
try {
object.wait();
System.out.println(System.currentTimeMillis() + " - Thread1 after wait()");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " - Thread1 ending");
}
};
Runnable thread2 = () -> {
synchronized (object) {
System.out.println(System.currentTimeMillis() + " - Thread2 inside synchronized block");
try {
Thread.sleep(2000);
System.out.println(System.currentTimeMillis() + " - Thread2 after sleep");
object.notify();
System.out.println(System.currentTimeMillis() + " - Thread2 after notify()");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " - Thread2 ending");
}
};
public void run() {
Thread t1 = new Thread(thread1);
Thread t2 = new Thread(thread2);
t1.start();
t2.start();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
t1.interrupt();
}
public static void main(String[] args) {
new Test().run();
}
}
I couldn't understand the result. Firstly, why is the exception stack trace not showing on the third line of the output? The first thread was interrupted while the second thread was still sleeping, so the exception should occur before the second thread woke up. Secondly, why is "Thread 1 ending" showing up before the stack trace?
1643099950931 - Thread1 inside synchronized block
1643099950947 - Thread2 inside synchronized block
1643099952947 - Thread2 after sleep
1643099952947 - Thread2 after notify()
1643099952947 - Thread2 ending
1643099952947 - Thread1 ending
java.lang.InterruptedException
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Object.wait(Object.java:328)
at com.ocbc.ms.Test.lambda$new$0(Test.java:13)
at java.base/java.lang.Thread.run(Thread.java:834)
From the documentation of Thread.wait (relevant part highlighted in bold):
Causes the current thread to wait until it is awakened, typically by being notified or interrupted, or until a certain amount of real time has elapsed.
...
This method causes the current thread (referred to here as T) to place itself in the wait set for this object and then to relinquish any and all synchronization claims on this object.
Thread T then becomes disabled for thread scheduling purposes and lies dormant until one of the following occurs:
...
Some other thread interrupts thread T.
...
The thread T is then removed from the wait set for this object and re-enabled for thread scheduling. It competes in the usual manner with other threads for the right to synchronize on the object; once it has regained control of the object, all its synchronization claims on the object are restored to the status quo ante - that is, to the situation as of the time that the wait method was invoked. Thread T then returns from the invocation of the wait method. Thus, on return from the wait method, the synchronization state of the object and of thread T is exactly as it was when the wait method was invoked.
In other words, when thread 1 is interrupted by the main thread, it still has to wait for thread 2 to finish to relinquish its lock, and only then thread 1 will regain control of the lock and continue.
Related
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.
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?
It might seem to be a very naive question but I cannot find any concrete answer anywhere. I tried it even practically but since we cannot predict the behaviour of threads resource allocation in Java, it's really difficult to determine.
I just want to know if I can access a synchronized method and and unsynchronized method of a class at the same time from two different threads of same instance of that class ?
Don't see any problems. Try out this:
public class Main {
public static final SyncNotsynced sn = new SyncNotsynced();
public static void main(String[] args){
Thread t1 = new Thread(sn::synced);
Thread t2 = new Thread(sn::notsynced);
t1.start();
t2.start();
}
public static class SyncNotsynced {
public synchronized void synced(){
System.out.println(Thread.currentThread().getName() + " enter synced");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " exit synced");
}
public void notsynced(){
System.out.println(Thread.currentThread().getName() + " enter notsynced");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println(Thread.currentThread().getName() + " exit notsynced");
}
}
}
or take look at the live example :). As you can see enterings of Thread 1 and Thread 2 are both happened before exiting:
Thread-0 enter synced
Thread-1 enter notsynced
Thread-0 exit synced
Thread-1 exit notsynced
For a formal explanation you can read JLS 17, but in short only one thread can enter a synchronized block on the same object monitor.
Btw, I used Thread.sleep because (emphasize mine):
Thread.sleep causes the currently executing thread to sleep
(temporarily cease execution) for the specified duration, subject to
the precision and accuracy of system timers and schedulers. The thread
does not lose ownership of any monitors, and resumption of execution
will depend on scheduling and the availability of processors on which
to execute the thread.
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");
}
}
}
};
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.