Understanding deadlock with a simple example - java

I am working on understanding deadlock basics so I came up with below code. I have two threads acquiring locks in opposite order but they're not deadlocking. When I run it I see all the printouts. What am I doing wrong?
public class DeadlockBasics {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public static void main(String[] args) {
DeadlockBasics dk = new DeadlockBasics();
dk.execute();
}
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
// called by thread 1
public void processThis() {
lockA.lock();
// process resource A
System.out.println("resource A -Thread1");
lockB.lock();
// process resource B
System.out.println("resource B -Thread1");
lockA.unlock();
lockB.unlock();
}
// called by thread 2
public void processThat() {
lockB.lock();
// process resource B
System.out.println("resource B -Thread2");
lockA.lock();
// process resource A
System.out.println("resource A -Thread2");
lockA.unlock();
lockB.unlock();
}
}

First of all there is no garantee which threads is start first. To get the deadlock one of the thread has to take a lock on lockA and then the second thread has to take a lock on lockB or visa versa.
public void processThis() {
lockA.lock();
// here the control should be switched to another thread
System.out.println("resource A -Thread1");
lockB.lock();
...
But there may not be enough time to switch between thread because you have just a few lines of code.. It is too fast. To emulate some long work add delay before the second lock to both methods
lockA.lock();
Thread.sleep(200); // 200 milis
Then the second thread will be able to lock lockB before the first release both of them

This could indeed result in a deadlock but not always, for example if the processThis() is completely executed and then the processThat() or vice versa there is no deadlock. You can try to add a Thread.delay(100) or a Thread.yield() to steer the threads execution towards the deadlock or even removing the unlocks to a certain deadlock.

Your code is a good example of dead lock, since ReenttrantLock is a mutual exclusion lock with same behavior as the implicit monitor lock access by using synchronized. However you don't see the deadlock because of this part:
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
After the first thread is created and started, it will takes a while to create the second thread. It takes the JVM about 50 us or maybe even less to create a new thread, it sounds very short, but it is enough for the first thread to be finished and therefore a dead lock will not happen.
I added a Thread.sleep(); into your code so the both threads could be executed somehow parallely.
package com.company;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class DeadlockBasics {
private Lock lockA = new ReentrantLock();
private Lock lockB = new ReentrantLock();
public static void main(String[] args) {
DeadlockBasics dk = new DeadlockBasics();
dk.execute();
}
private void execute() {
new Thread(this::processThis).start();
new Thread(this::processThat).start();
}
// called by thread 1
private void processThis() {
lockA.lock();
// process resource A
try {
Thread.sleep(1000); //Wait for thread 2 to be executed
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 1 will own lock a");
lockB.lock();
// process resource B
System.out.println("Thread 1 will own lock b");
lockA.unlock();
lockB.unlock();
// Both locks will now released from thread 1
}
// called by thread 2
private void processThat() {
lockB.lock();
// process resource B
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread 2 will own lock b");
lockA.lock();
// process resource A
System.out.println("Thread 2 will own lock a");
lockA.unlock();
lockB.unlock();
// Both locks are released by thread 2
}
}

Two points:
Release locks in the reverse order of acquiring them. That is, processThis should reverse the order of removing the locks. For your example, the order doesn't matter. But if processThis attempted to acquire a new lock on A before releasing the lock on B a deadlock could again occur. More generally, you'll find it easier to think about locks by considering their scope and by avoiding overlapping but non-enclosing scopes.
To better highlight the problem, I would put in call to wait after acquiring the first lock in each of threads, and have execute launch both threads then invoke notify on both threads.

Related

Join a two different ExecutorService

I wanted to join two threads that are getting executed in ExecutorService.
public class CURD {
public static ExecutorService executorService = Executors.newCachedThreadPool();
#Autowired
Logging logging;
public void Update(List<? extends HBase> save, List<? extends HBase> delete) {
Thread t = new Thread(() -> {
System.out.println("Started Main Thread...");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("End Main Thread...");
},"Thread-1");
logging.setPredecessor(t);
executorService.submit(t);
}
}
Second Class:
This class thread should wait for the first thread to complete.
But it doesn't wait for the first thread to complete.
I am not sure if this is the right way to do it.
Please can someone let me know how to join two threads that are getting executed in an ExecutorService?
import static com.demo.executorService;
public class Logging {
private Thread predecessor;
public void setPredecessor(Thread t) {
this.predecessor = t;
}
private void loggingInfo() {
Thread run = new Thread( () ->{
try {
if (predecessor != null) {
System.out.println(Thread.currentThread().getName() + " Started");
predecessor.join();
System.out.println(Thread.currentThread().getName() + " Finished");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
addTask(run);
}
public void addTask(Runnable run) {
System.out.println("Runnable Thread logAround.....");
CompletableFuture.runAsync((run), executorService).exceptionally(ex -> {
System.out.println("exception occurred " + ex);
return null;
});
}
}
If one wants to synchronize among a set of threads one can use
the Java CyclicBarrier class:
A synchronization aid that allows a set of threads to all wait for
each other to reach a common barrier point. CyclicBarriers are useful
in programs involving a fixed sized party of threads that must
occasionally wait for each other. The barrier is called cyclic because
it can be re-used after the waiting threads are released.
To achieve that, first create the CyclicBarrier object with the correspondent number of parties, namely:
private final CyclicBarrier barrier = new CyclicBarrier(NUMBER_OF_PARIES);
Formally from the Java doc one can read that parties are:
the number of threads that must invoke {#link #await} before the barrier is tripped
Informally, parties are the number of threads that will have to call the cyclic barrier and wait, before all of them can move forward.
Afterward, you need to pass the barrier instance object reference to each of the threads that should wait, and invoke wait (i.e., barrier.await()), accordingly. Something as follows:
public void Update(..., CyclicBarrier barrier) {
Thread t = new Thread(() -> {
System.out.println("Started Main Thread...");
try {
Thread.sleep(1500);
barrier.await(); // <--- wait on the barrier
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("End Main Thread...");
},"Thread-1");
...
}
Repeat this process to the other threads that must wait. Ensure that the number of parties (i.e., NUMBER_OF_PARIES) matches the number of threads that should wait on the cyclic barrier, otherwise deadlocks will occur.
Now that you are using the cyclic barrier you can clean up some parts of your code, for instance, you can remove all the logic related to the field predecessor of the Logging class.
If you just want to make Thread 2 wait for Thread 1, then you can use CountDownLatch, instead.
A synchronization aid that allows one or more threads to wait until a
set of operations being performed in other threads completes. A
CountDownLatch is initialized with a given count. The await methods
block until the current count reaches zero due to invocations of the
countDown() method, after which all waiting threads are released and
any subsequent invocations of await return immediately. This is a
one-shot phenomenon -- the count cannot be reset. If you need a
version that resets the count, consider using a CyclicBarrier.
First create the CountDownLatch object with only 1 count:
private final CountDownLatch block_thread2 = new CountDownLatch(1);
and pass it to the Thread 2, and since you want this thread to wait for the Thread 1, call block_thread2.await();
Thread run = new Thread( () ->{
try {
....
block_thread2.await(); // wait for Thread 2
} catch (InterruptedException e) {
// deal with it
}
});
...
and to the Thread 1 add wait.countDown();:
public void Update(...) {
Thread t = new Thread(() -> {
System.out.println("Started Main Thread...");
try {
Thread.sleep(1500);
wait.countDown();
} catch (InterruptedException e) {
// deal with it
}
System.out.println("End Main Thread...");
},"Thread-1");
...
}
So, in this manner, Thread 2 will wait for Thread 1, but Thread 1 will never wait for Thread 2.

Best way to block other threads until one is finished

I have many threads which monitor a certain state. If the application gets into that state, then I need to do some extra work. I want to allow just 1 thread to execute that and want to block the others until that work is finished. Blocking mean, that they must not execute that task again.
I have the following scenario:
ReentrantLock lock = new ReentrantLock
void doSomething() {
if (lock.tryLock()) {
try {
doSomeWork()
} finally {
lock.unLock()
}
} else {
// wait for DoSomeWork is done
}
}
I can monitor lock.isLocked() in a loop, but actually I just want to have some sort of wait until the work is finished by the other thread.
According to documentation about ReentrantLock class:
It is recommended practice to always immediately follow a call to
lock with a try block, most typically in a before/after construction
such as:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
From the documentation for lock() method:"If the lock is held by another thread then the current thread becomes disabled for thread scheduling purposes and lies dormant until the lock has been acquired" and this is what you want to be guaranteed in your scenario.

What will be if reassign reference to lock object inside synchronization block?

NOTE: Invalid question - see comment of #Bukhtoyarov Vladimir
Let's say we have the following code:
public class Main {
private Object monitor = new Object();
public static void main(String[] args) throws InterruptedException {
Main main = new Main();
main.test();
new Thread() {
#Override
public void run() {
try {
main.changeMonitor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
private void test() throws InterruptedException {
synchronized (monitor) {
Thread.sleep(100);
monitor = new Object();
Thread.sleep(1000);
System.out.println("test finished");
}
}
private void changeMonitor() throws InterruptedException {
Thread.sleep(600);
monitor = new Object();
System.out.println("monitor changed");
}
}
Here we have two threads - main thread and another worker thread. Also we have monitor object. Inside worker thread we have next sequence of actions -
acquire lock on monitor
wait 100ms
assign monitor reference to point a new object
wait another 1000ms
In main thread we are waiting 600ms and try to reassign monitor to a new object.
As the result - main thread is blocked - till worker thread releases lock on the monitor object.
Here i have two questions
According to the Concurrency in practice book - the only way to be blocked by the lock aquision process - is to enter synchronization block. So why main thread is blocked till worker thread releases lock - in main thread we are not trying to enter synchronization block
Worker thread assign new object to monitor reference after 100ms, why main thread can not acquire lock on new reassigned object after 600ms ? I mean - after 600ms in monitor ref is new object - so lock should be ready to be gained
The behavior is interesting - as i can not find any information about it in official Oracle docs or Concurrency in practice book.
This code
synchronized (monitor) {
is like
Object m = monitor;
synchronized (m) {
i.e. the read only happens once, and in a context which is not thread-safe.
why main thread can not lock on new object - reassigned inside worker thread.
This means
once it has obtained an object to lock on to, it doesn't keep reading the latest value in a loop to see if it can lock on another object.
even if the reference is changed before the read, it could see an old value, as the read is not thread safe.

Deadlocks using wait and notify

I am trying to understand how deadlocks are created. I've understood that by using two threads on two synchronized methods, a deadlock can be created.
Went through many examples from the net.
Can a deadlock be created with wait and notify?
Every time a thread is on wait, it will be notified. So how does this end up in a deadlock?
Illustration of an example will be helpful.
Deadlock is caused when two threads try to obtain the same, multiple locks in different order:
// T1
synchronized (A) {
synchronized (B) {
// ...
}
}
// T2
synchronized (B) {
synchronized (A) {
// ...
}
}
The only way to prevent deadlocks is to make sure that all threads obtain locks in the same order--either they all do A then B, or they all do B then A.
If you don't have multiple locks, then you don't have a deadlock. However, you can get thread starvation or other things that may look similar to deadlock.
Say thread 1 enters a synchronized block on method A and then waits. Thread 2 then attempts to enter the synchronized block on method A. Thread 1 is waiting for a notify, and thread 2 is waiting on the synchronized block. Everything is now waiting. Some other thread will have to notify the object on which thread 1 is waiting. This is just one scenario that can create a deadlock. There are all kinds of ways to do it.
A thread which is on wait will not be notified unless some code explicitly notifies it. Therefore the example you are looking for is absolutely trivial:
public static void main(String[] args) {
synchronized(String.class) {
String.class.wait();
}
}
and this hangs forever. Technically, though, it is not a deadlock, which requires two or more threads involved in a closed cycle where each thread waits for the next one to unblock it.
Something close to wait/notify deadlock:
public class Example
{
volatile boolean isNotified = false;
public synchronized void method1() {
try
{
isNotified = false;
while (!isNotified)
wait();
notifyAll();
System.out.println("Method 1");
} catch (InterruptedException e) {/*NOP*/}
}
public synchronized void method2() {
try {
isNotified = true;
while (isNotified)
wait();
notifyAll();
System.out.println("Method 2");
} catch (InterruptedException e) {/*NOP*/}
}
public static void main(String[] args)
{
Example example = new Example();
Thread thread1 = new Thread()
{
public void run()
{
example.method1();
}
};
Thread thread2 = new Thread()
{
public void run()
{
example.method2();
}
};
thread1.start();
thread2.start();
}
}

Reentrant lock and deadlock with Java

Can someone explain to me how Reentrant lock and deadlock relate to each other with Java code (pseudo) example?
A reentrant locking mechanism allows the thread holding the lock to re-enter a critical section. This means that you can do something like this:
public synchronized void functionOne() {
// do something
functionTwo();
// do something else
// redundant, but permitted...
synchronized(this) {
// do more stuff
}
}
public synchronized void functionTwo() {
// do even more stuff!
}
In a non-reentrant lock, you would have a deadlock situation when you try to call functionTwo() from functionOne() because the thread would have to wait for the lock...which it holds itself.
Deadlock, of course, is the evil situation in which Thread 1 holds lock A and is waiting for lock B while Thread 2 holds lock B and is waiting for lock A. Thus, neither can continue. This code sample creates a deadlock:
public synchronized void deadlock() throws InterruptedException {
Thread th = new Thread() {
public void run() {
deadlock();
}
}.start();
th.join();
}
The calling thread tries to wait around for the spawned thread, which in turn can't call deadlock() until the caller has exited. Ka-boom!
A deadlock occurs when a thread waits for a condition which will never become true.
The obvious case is when you are trying to lock two locks, locked in a different order by different threads.
ReentrantLock lock1 = new ReentrantLock();
ReentrantLock lock2 = new ReentrantLock();
public void methodA() {
lock1.lock();
lock2.lock();
// do something and unlock both.
}
public void methodB() {
lock2.lock();
lock1.lock();
// do something and unlock both.
}
As you can see it is possible for a thread to call methodA and obtain lock1 waiting for lock2, and another thread to call methodB and obtain lock2 waiting for lock1.
However, it's possible for a thread to deadlock itself. An example is ReentrantReadWriteLock because it doesn't support upgrading a read lock to a write lock.
ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
rwl.readLock().lock();
// do we need to update?
rwl.writeLock().lock(); // will wait for the readLock() to be released!
An obscure opportunity to deadlock yourself is when implied locks are used. A static initialiser block is implicitly thread-safe so a lock is used even though static initialiser blocks are not synchronized
class A {
private static int VALUE;
static {
Thread t = new Thread() {
public void run() {
// waits for the A class to load.
VALUE = someLongTask();
}
};
t.start();
// waits for the thread.
t.join();
}
}
Again you have a deadlock!
Here's an example of deadlock with ReentrantLock
class Deadlock {
private static final ReentrantLock l1 = new ReentrantLock();
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("A Trying to lock...");
l1.lock();
System.out.println("A Locked...");
try {
Thread t = new Thread(new Runnable() {
public void run() {
System.out.println("B Trying to lock...");
l1.lock();
System.out.println("B Must not print");
try {
} finally {
System.out.println("B Trying to unlock...");
l1.unlock();
System.out.println("B Unlocked...");
}
}
});
t.start();
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
System.out.println("A Trying to unlock...");
l1.unlock();
System.out.println("A Unlocked...");
}
}
});
t.start();
}
}
To resolve deadlock, comment out call to t.join, along with enclosing try/catch.
A reentrant lock will allow the lock holder to enter blocks of code even after it has already obtained the lock by entering other blocks of code. A non-reentrant lock would have the lock holder block on itself as it would have to release the lock it obtained from another block of code to reobtain that same lock to enter the nested lock requiring block of code.
As far as deadlock is concerned, if you call a protected block of code from a protected block of code, you'll want a reentrant lock (or you will deadlock while waiting on yourself).

Categories

Resources