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?
Related
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.
I'm trying to learn java multithreading, and this is a simple leetcode concurrency problem (https://leetcode.com/problems/print-foobar-alternately/). I came up with the following code, but I don't understand why it works. The problem says one thread call foo and one thread call bar, and it should print "foobar" n times.
public class Foobar {
int n;
boolean hasFoo;
Lock lock;
Condition cond;
public Foobar(int n) {
this.n = n;
hasFoo = false;
lock = new ReentrantLock();
cond = lock.newCondition();
}
public void foo(Runnable printFoo) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
while (hasFoo) {
cond.await();
}
printFoo.run();
hasFoo = true;
cond.signalAll();
lock.unlock();
}
}
public void bar(Runnable printBar) throws InterruptedException {
for (int i = 0; i < n; i++) {
lock.lock();
while (!hasFoo) {
cond.await();
}
printBar.run();
hasFoo = false;
cond.signalAll();
lock.unlock();
}
}
}
It works, but I don't understand why. From my understanding, if the "bar" thread runs first and acquires the lock, it should wait and the "foo" thread will block in the lock.lock(); line, but it turns out they both enter the locked part. Please enlighten me where I misunderstand lock in java.
Here is how I call these two methods.
Foobar f = new Foobar(10);
Runnable rf = () -> {
try {
f.foo(() -> System.out.println("foo"));
} catch (Exception e) {
e.printStackTrace();
}
};
Runnable rp = () -> {
try {
f.bar(() -> System.out.println("bar"));
} catch (Exception e) {
e.printStackTrace();
}
};
Thread t1 = new Thread(rf, "foo-thread");
Thread t2 = new Thread(rp, "bar-thread");
t1.start();
t2.start();
if the "bar" thread runs first and acquires the lock, it should wait ...
Wait for what? The "bar" thread is the first that acquired the lock, there is nothing to wait for. This thread will immediately proceed to the next statement, which is cond.await(); where the lock will be released1, and the thread will go to sleep.
In the meanwhile, the "foo" thread can acquire the lock2, and print its message, and notify others that its job is done, which, subsequently, unlocks3 the sleeping "bar".
... the "foo" thread will be blocked in the lock.lock();
Exactly.
but it turns out they both enter the locked part.
No. One entered, another is waiting to enter. It's a simple lock - only one thread can acquire it at a time (it's like an advanced version of the synchronized statement).
1 The lock associated with this Condition is atomically released and the current thread becomes disabled for thread scheduling purposes and lies dormant
https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/concurrent/locks/Condition.html#await()
2 Remember, it was blocked since it tried to acquire the lock shorty after the "bar" did it.
If the lock is not available then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired.
https://docs.oracle.com/en/java/javase/12/docs/api/java.base/java/util/concurrent/locks/Lock.html#lock()
3 By signalling to all, which one of the four methods to awake others.
Some other thread invokes the signalAll() method for this Condition;
https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/Condition.html#await()
Her in bar(), Lock.lock() takes the lock but Condition.await() makes the thread waiting for and releases the lock too .
Condition.await() specifying (emphasis is mine) :
Causes the current thread to wait until it is signalled or
interrupted.
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:
So supposing that bar() is executed before foo() :
public void bar(Runnable printBar) throws InterruptedException {
// ...
while (!hasFoo) { // true
cond.await(); // release the lock and wait
}
// ...
}
So bar() waits but foo() goes further in its execution and prints foo :
public void foo(Runnable printFoo) throws InterruptedException {
//...
while (hasFoo) { // false
cond.await();
}
// We print first so
}
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 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");
}
Why usually threading samples put so many code in synchronized block. According to my understanding in following case synchronized is used just for locking b for wait and notify:
Main class ThreadA :
class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
synchronized(b) {
try {
System.out.println("Waiting for b to complete...");
b.wait();
} catch (InterruptedException e) {}
System.out.println("Total is: " + b.total);
System.out.println(Thread.currentThread().getName());
}
}
}
and class ThreadB:
class ThreadB extends Thread {
int total;
public void run() {
synchronized(this)
{
System.out.println();
for(int i=0;i<100;i++)
{
System.out.println(Thread.currentThread().getName());
total += i;
}
notify();
}
}
}
What will change if I put just wait and notify in synchronized block:
class ThreadA {
public static void main(String [] args) {
ThreadB b = new ThreadB();
b.start();
try {
System.out.println("Waiting for b to complete...");
synchronized(b) { b.wait();}
} catch (InterruptedException e) {}
System.out.println("Total is: " + b.total);
System.out.println(Thread.currentThread().getName());
}
}
According to my understanding in following case synchronized is used just for locking b for wait and notify
Your understanding is wrong.
synchronized is also used for:
Mutual exclusion, to ensure that only one thread executes code "guarded" by a particular monitor at a time
Ensuring memory access across threads is correct (that one thread sees changes made by another thread)
What will change if I put just wait and notify in synchronized block:
In this particular case, it will make a difference based on a race condition - in the original code, if the new thread starts executing before the synchronized block is reached in the original thread, it won't get as far as "Waiting for b to complete" until the second thread has finished... at which point it will block forever in wait.
Note that it's a really bad idea to wait on Thread monitors, as wait/notify is used internally by Thread.
In short, the example you've used is a bad one to start with in various ways - but synchronization is used for more than just wait/notify.
Please note that total += i is not an atomic operation in Java. So you have to sync also this construct.
You also have not to sync notify() and wait() because their locks are handled internally.
Expanding on the answer by #sk2212, the increment operation is not atomic, but there is an equivalent atomic operation provided in high-level concurrency primitives.