Testing a potential deadlock without sleep in JUnit - java

In classical Deadlock example, there are two paths in the code acquiring the same two synchronized locks, but in different order like here:
// Production code
public class Deadlock {
final private Object monitor1;
final private Object monitor2;
public Deadlock(Object monitor1, Object monitor2) {
this.monitor1 = monitor1;
this.monitor2 = monitor2;
}
public void method1() {
synchronized (monitor1) {
tryToSleep(1000);
synchronized (monitor2) {
tryToSleep(1000);
}
}
}
public void method2() {
synchronized (monitor2) {
tryToSleep(1000);
synchronized (monitor1) {
tryToSleep(1000);
}
}
}
public static void tryToSleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
This could potentially result in a deadlock. To increase the chance that it actually deadlocks, I am adding those tryToSleep(1000);, just to ensure that method1 will acquire a lock on monitor1, and method2 will acquire the lock on monitor2, before even trying to acquire next lock. So using the sleep this Deadlock simulates "unlucky" timing. Say, there is a strange requirement, that our code should have the potential to result in a deadlock, and for that reason, we want to test it:
// Test
#Test
void callingBothMethodsWillDeadlock() {
var deadlock = new Deadlock(Integer.class, String.class);
var t1 = new Thread(() -> {
deadlock.method1(); // Executes for at least 1000ms
});
t1.start();
var t2 = new Thread(() -> {
deadlock.method2(); // Executes for at least 1000ms
});
t2.start();
Deadlock.tryToSleep(5000); // We need to wait for 2s + 2s + some more to be sure...
assertEquals(Thread.State.BLOCKED, t1.getState());
assertTrue(t1.isAlive());
assertEquals(Thread.State.BLOCKED, t2.getState());
assertTrue(t2.isAlive());
}
This passes, which is good. Which is not good is that I had to add sleep into the Deadlock class itself, and also in its test. I had to do this just in order to make the test consistently pass. Even though if I remove sleep from everywhere this code could sometimes produce a deadlock, but then there is no guarantee that it happens during the test. Now say having sleep is unacceptable here, then the question is:
How can I reliably test that this code, has a potential to cause a deadlock without any sleep neither in the test and in the actual code itself?
edit: I just wanted to emphasize that I am asking for the class to have a potential for a deadlock, only in some "unlucky" timing (when two threads are calling method1() and method2() at the same time) this deadlock should happen. And in my test, I want to demonstrate deadlock on every run. I want to remove sleep calls from the production code (hopefully from the test also). Maybe there is a way to use mocks instead of the injected monitors, so we could orchestrate them acquiring locks in a specific order during the test?

Essentially, you need Thread (t1) executing method1 to wait inside synchronized (monitor1) but outside ofsynchronized (monitor1) until another Thread (t2) executing method2 goes inside synchronized (monitor2) and releases t1 and both threads try to proceed.
Or vice versa, where t2 waits until t1 comes and releases
You can code this scenario yourself. But since you are focusing just on Deadlock testing, you can use a java.util.concurrent.CyclicBarrier between 2 parties to orchestrate this, where parties indicate the number of threads that must invoke CyclicBarrier.await() before the barrier is tripped (in other words, all the threads previous awaiting proceeds).
class Deadlock {
final private CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
final private Object monitor1;
final private Object monitor2;
public Deadlock(Object monitor1, Object monitor2) {
this.monitor1 = monitor1;
this.monitor2 = monitor2;
}
public void method1() throws BrokenBarrierException, InterruptedException {
synchronized (monitor1) {
cyclicBarrier.await();
synchronized (monitor2) {
}
}
}
public void method2() throws BrokenBarrierException, InterruptedException {
synchronized (monitor2) {
cyclicBarrier.await();
synchronized (monitor1) {
}
}
}
public static void tryToSleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
You will have to handle the checked Exceptions threw by cyclicBarrier.await()
Thread t1 = new Thread(() -> {
try {
deadlock.method1();
} catch (BrokenBarrierException | InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
Thread t2 = new Thread(() -> {
try {
deadlock.method2();
} catch (BrokenBarrierException | InterruptedException e) {
e.printStackTrace();
}
});
t2.start();
deadlock.tryToSleep(5000); // Wait till all threads have a chance to become alive
assertEquals(Thread.State.BLOCKED, t1.getState());
assertTrue(t1.isAlive());
assertEquals(Thread.State.BLOCKED, t2.getState());
assertTrue(t2.isAlive());

Related

Using synchronized blocks, notify() and wait() the right way

I'm curious to submit here a short example I made and hopefully have someone able to explain to me one thing: is it possible to use the wait() and notify() inside a synchronized block without having to declare threads explicitly? (AKA: not using dedicated threads).
Here's the example:
public class mutex {
private Object mutex = new Object();
public mutex(Object mutex) {
this.mutex = mutex;
}
public void step1() throws InterruptedException {
System.out.println("acquiring lock");
synchronized(mutex) {
System.out.println("got in sync block");
System.out.println("calling wait");
mutex.wait();
System.out.println("wait finished ");
}
}
public void step2() throws InterruptedException{
System.out.println("acquiring lock");
synchronized(mutex){
System.out.println("got in sync block");
System.out.println("calling notify");
mutex.notify();
System.out.println("notify called");
}
}
Those two simple step are just prints for logging and what should be happening.
The idea is to be able to call a wait() in step1 and be able to complete the call once step2 has been called with its notify().
Now, as far as I understood the whole thing, this is the right way to do what I want to do:
public void go1() {
Object mutex = new Object();
mutex m = new mutex(mutex);
Thread t1 = new Thread(()->{
try {
m.step1();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(()->{
try {
Thread.sleep(1000);
m.step2();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
}
and finally the main
public static void main(String[] args) {
Object mutex = new Object();
new mutex(mutex).go1();
//new mutex(mutex).go2();
}
The above code works and shows what I am expecting:
acquiring lock
got in sync block
calling wait
acquiring lock
got in sync block
calling notify
notify called
wait finished
I get why it works. This is what I expected to happen and how I have been taught to do this. The question comes now as I will paste the second variant of the main function I wanted to test - this one just hangs when the wait() is called.
public void go2() {
Object mutex = new Object();
mutex m = new mutex(mutex);
try {
m.step1();
Thread.sleep(1000);
m.step2();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Why does this hang?
Is it because there is just one thread doing everything and it goes into waiting state after the wait() is called?
I know that when wait is called on the monitor object it should also release the lock, so why in this case the program can't get to call the step2()?
Is there a way to use the my second go() function to achieve this process or is it impossible for it to work?
TLDR just so I am making sure I can be understood: do I have to use dedicated threads to also use properly wait() and notify()? Because I seem to get deadlocks if I don't.
Thank you.
Once you call mutex#wait, the current thread is added to the wait set of object mutex. And thread will not execute any further instructions until it has been removed from mutex's wait set. That's why step2 cannot be executed by the current thread.
The current thread will be removed from the wait set and resume if other threads call mutex#notify/notifyAll. See JLS#WAIT for all situations in which the current thread can resume..

Why does another thread get access to blocked object while synchronized section has not completed?

The message "main Thread" is printed before message "new Thread" though method with message "new Thread" is in syncronized section by object which include print* methods.
Test test = new Test();
new Thread(() -> {
try {
synchronized (test) {
Thread.sleep(5000);
test.printMessage();
}
} catch (InterruptedException e) {}
}).start();
Thread.sleep(1000);
test.printAnotherMessage();
}
public void printMessage() {
System.out.println("new Thread");
}
public void printAnotherMessage() {
System.out.println("main Thread");
}
}
In this example there is no synchronization between printAnotherMessage and the synchronized block that sleeps for 5 seconds, that's why main thread sleeps for 1 second and then prints main Thread without any waiting.
You probably intended to make printAnotherMessage a synchronized method.
In this case main thread will wait till the other thread finishes the execution of the block synchronized on test object.
There is no synchronisation on test.printAnotherMessage(); so it will be executed first assuming the timing is right. 4 seconds is a lot and should be enough.
synchronized (test) {
test.printAnotherMessage();
}
Thread.sleep is rarely a good option, though. A more proper way would be
Test test = new Test();
new Thread(() -> {
synchronized (test) {
test.printMessage();
test.notify();
}
}).start();
synchronized (test) {
test.wait();
test.printAnotherMessage();
}
I am playing a dangerous game here since I am assuming the main thread will enter the synchronized block and execute wait() before another thread is created and it enters its synchronized block. It's reasonable since creating a thread will take some time.
Test test = new Test();
new Thread(() -> {
try {
// a lot of time to let the main thread execute wait()
Thread.sleep(500);
synchronized (test) {
test.printMessage();
test.notify();
}
} catch (InterruptedException e) {}
}).start();
synchronized (test) {
test.wait();
test.printAnotherMessage();
}

How to ensure that `methodB` is "blocked" if some threads are in `methodA` in Java?

Class clazz has two methods methodA() and methodB().
How to ensure that methodB is "blocked" if some threads are in methodA in Java (I am using Java 8)?
By "blocking methodB", I mean that "wait until no threads are in methodA()". (Thanks to #AndyTurner)
Note that the requirement above allows the following situations:
Multiple threads are simultaneously in methodA.
Multiple threads are in methodB while no threads are in methodA.
Threads in methodB does not prevent other threads from entering methodA.
My trial: I use StampedLock lock = new StampedLock.
In methodA, call long stamp = lock.readLock()
Create a new method unlockB and call lock.unlockRead(stamp) in it.
In methodB, call long stamp = lock.writeLock() and lock.unlockWrite(stamp).
However, this locking strategy disallows the second and the third situations above.
Edit: I realize that I have not clearly specified the requirements of the synchronization between methodA and methodB. The approach given by #JaroslawPawlak works for the current requirement (I accept it), but not for my original intention (maybe I should first clarify it and then post it in another thread).
I think this can do the trick:
private final Lock lock = new ReentrantLock();
private final Semaphore semaphore = new Semaphore(1);
private int threadsInA = 0;
public void methodA() {
lock.lock();
threadsInA++;
semaphore.tryAcquire();
lock.unlock();
// your code
lock.lock();
threadsInA--;
if (threadsInA == 0) {
semaphore.release();
}
lock.unlock();
}
public void methodB() throws InterruptedException {
semaphore.acquire();
semaphore.release();
// your code
}
Threads entering methodA increase the count and try to acquire a permit from semaphore (i.e. they take 1 permit if available, but if not available they just continue without a permit). When the last thread leaves methodA, the permit is returned. We cannot use AtomicInteger since changing the count and acquiring/releasing permit from semaphore must be atomic.
Threads entering methodB need to have a permit (and will wait for one if not available), but after they get it they return it immediately allowing others threads to enter methodB.
EDIT:
Another simpler version:
private final int MAX_THREADS = 1_000;
private final Semaphore semaphore = new Semaphore(MAX_THREADS);
public void methodA() throws InterruptedException {
semaphore.acquire();
// your code
semaphore.release();
}
public void methodB() throws InterruptedException {
semaphore.acquire(MAX_THREADS);
semaphore.release(MAX_THREADS);
// your code
}
Every thread in methodA holds a single permit which is released when the thread leaves methodA.
Threads entering methodB wait until all 1000 permits are available (i.e. no threads in methodA), but don't hold them, which allows other threads to enter both methods while methodB is still being executed.
You can't really prevent that methodA or methodB is called (while other threads are inside the other method) but you can implement thread intercommunication in such a way so that you can still achieve what you want.
class MutualEx {
boolean lock = false;
public synchronized void methodA() {
if (lock) {
try {
wait();
}catch (InterruptedException e) {
}
}
//do some processing
lock = true;
notifyAll();
}
public synchronized void methodB() {
if (!lock) {
try {
wait();
}catch (InterruptedException e) {
}
}
//do some processing
lock = false;
notifyAll();
}
}
Now, for this to work any Thread object you create should have a reference to the same instance of MutualEx object.
Why not using an kind of external orchestrator?
I mean another class that will be responsible to call the methodA or methodB when it allowed.
Multi-thread can still be handle via locking or maybe just with some AtomicBoolean(s).
Please find below a naive draft of how to do it.
public class MyOrchestrator {
#Autowired
private ClassWithMethods classWithMethods;
private AtomicBoolean aBoolean = = new AtomicBoolean(true);
public Object callTheDesiredMethodIfPossible(Method method, Object... params) {
if(aBoolean.compareAndSet(true, false)) {
return method.invoke(classWithMethods, params);
aBoolean.set(true);
}
if ("methodA".equals(method.getName())) {
return method.invoke(classWithMethods, params);
}
}
}
In very simple terms what you all need is ENTER methodB only if no thread inside methodA.
Simply you can have a global counter, first initialized to 0 to record the number of threads that are currently inside methodA(). You should have a lock/mutex assigned to protect the variable count.
Threads entering methodsA do count++.
Threads exiting methodA do count-- .
Threads that are entering methodB first should check whether count == 0.
methodA(){
mutex.lock();
count++;
mutex.signal();
//do stuff
mutex.lock();
count--;
mutex.signal();
}
methodB(){
mutex.lock();
if(count != 0){
mutex.signal();
return;
}
mutex.signal();
//do stuff
}
You would need an int to count threads in methodA, and ReentrantLock.Condition to signal all threads waiting in methodB once there are no threads in methodA:
AtomicInteger threadsInMethodA = new AtomicInteger(0);
Lock threadsForMethodBLock = new ReentrantLock();
Condition signalWaitingThreadsForMethodB = threadsForMethodBLock.newCondition();
public void methodA() {
threadsInMethodA.incrementAndGet();
//do stuff
if (threadsInMethodA.decrementAndGet() == 0) {
try {
threadsForMethodBLock.lock();
signalWaitingThreadsForMethodB.signalAll();
} finally {
threadsForMethodBLock.unlock();
}
}
}
public void methodB() {
try {
threadsForMethodBLock.lock();
while (!Thread.isInterrupted() && threadsInMethodA.get() != 0) {
try {
signalWaitingThreadsForMethodB.await();
} catch (InterruptedException e) {
Thread.interrupt();
throw new RuntimeException("Not sure if you should continue doing stuff in case of interruption");
}
}
signalWaitingThreadsForMethodB.signalAll();
} finally {
threadsForMethodBLock.unlock();
}
//do stuff
}
So each thread entering methodB will first check if nobody in methodA, and signal previous waiting threads. On the other hand, each thread entering methodA will increment counter to prevent new threads doing work in methodB, and on decrement it will release all the threads waiting to do stuff in methodB if no threads left inside methodA.

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();
}
}

Notifying two threads at the same time

How can I notify Thread t1 and Thread t2 at the same time (so it is the same probability to get hey 1 as hey2 first)? I've tried notifyAll, but couldn't make it work.
class Thr extends Thread
{
Thr () throws InterruptedException
{
Thread t1 = new Thread() {
public synchronized void run()
{
while (true)
{
try {
wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try
{
Thread.sleep(1500);
} catch (Exception e) { }
System.out.println("hey 1");
}
}
};
Thread t2 = new Thread() {
public synchronized void run()
{
while (true)
{
try {
wait();
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try
{
Thread.sleep(1500);
} catch (Exception e) { }
System.out.println("hey 2");
}
}
};
t1.start();
t2.start();
}
public static void main(String args[]) throws InterruptedException
{
new Thr();
}
}
You should wait on a shared object and use notifyAll as in:
class Thr extends Thread
{
Thr () throws InterruptedException
{
final Object lock = new Object ();
Thread t1 = new Thread() {
public void run()
{
try {
synchronized (lock) {
lock.wait();
}
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("hey 1");
}
};
Thread t2 = new Thread() {
public synchronized void run()
{
try {
synchronized (lock) {
lock.wait();
}
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("hey 2");
}
};
t1.start();
t2.start();
synchronized (lock) {
lock.notifyAll ();
}
}
public static void main(String args[]) throws InterruptedException
{
new Thr();
}
}
The right way to do this is to use notifyAll. The real problem with your code seems to be that you have two threads waiting for notifications on different mutexes. You need them to wait on a single object ... as described in #ShyJ's answer.
Note that there is NO WAY that you can code this so that the notification is guaranteed to be delivered first to either thread with equal probability:
The Java threading specs make no guarantees of fairness in wait / notify.
The thread scheduler implemented (typically) at the OS-level (typically) makes no such guarantees either.
The point is that the application has no control over this. The best approach is to just let wait/notifyAll do what they normally do, and design your application so that any bias in the thread scheduling does not affect the application's behaviour in an important way.
(FWIW, the usual problem is that people explicitly or implicitly assume non-randomness ... and get burned when threads get scheduled in an unexpectedly random order.)
I highly recommend avoiding the use of wait/notify and use something more robust. The problem is that using wait/notify in any combination will likely result in a race condition.
The only way to give equal probability to them academically is to create two Semaphore objects, have the threads try to acquire them, and use Random to choose which one to release first. Even then, if the scheduler decides to run the first one that tried to obtain the lock, then you get bias there anyway, regardless of whether or not the Sempahore is fair. This forces you to wait until the first thread is done before running the second, such as via Thread.join.
Bottom line, the only way to guarantee order in a concurrent system is to force them into a single-threaded format, which throws out the whole point of having them concurrent in the first place.
If you are using Java versions greater than 1.4, then it would greatly simplyfy your task by using any of the concurrent locks:
java.util.concurrent.locks specially the ReadWrite type.
For now for message passing to all the threads at the same type - implement Observer Pattern

Categories

Resources