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

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..

Related

Creating lock object in main thread causing ANR

I've an object that's created when the class is instantiated. I create a lock i-e; wait() on that object inside a background thread, however the app still gets unresponsive. My understanding of synchronization/locking is that if object.wait() is called in the main thread than it's equivalent to blocking the main thread however if it's called inside a background thread (even though the object upon which wait() is called in the main thread, shouldn't cause problems).
Can someone please help me out understanding this?
Example code:
class MyClass {
private final Object myLockObject = new Object();
public void connect() {
new Thread(new Runnable{
mSocket.connect();
myLockObject.wait(); // causing ANR
}).start();
}
private void socketConnectCallback() {
//upon callback
myLockObject.notifyAll();
}
}
class MyAndroidService extends Service {
public void onStartCommand() {
MyClass myClassObject = new MyClass();
myClassObject.connect();
//it immediately returns here even with the code written above.
}
}
First of all, this code will throw an IllegalMonitorStateException. This is because before calling object.wait(), you need to make sure that you are holding the object's monitor. One way to do this is to use:
synchronised(object) {
// this thread now owns the object's monitor
object.wait();
}
Further, the thread that calls for object.wait() relinquishes its ownership on that object's monitor and waits for some other thread to notify it. Once it gets the notification, it will wait until it reacquires the object's monitor (since some other thread might be having the ownership of that monitor even if the waiting thread got the notify signal). Then it continues normal execution.
In your case, the background thread should block, and the main thread should continue executing normally. Isn't this what you have mentioned is happening?
I don't know if this will help so much, but I can't comment so I want to get your attention to this code:
newThread(new Runnable {
mSocket.connect();
myLockObject.wait();
}).start();
This must be like:
(new Thread( new Runnable() {
public void run() {
try {
mSocket.connect(); // connect takes argument(s)
} catch (IOException e) {
// Catch the excpetion
}
try {
myLockObject.wait();
} catch (InterruptedException e) {
// Catch the excpetion
}
}
})).start();
and since Runnable is a functional interface you can use lambda expression instead of creating a new object.
Edit:
I think I figured out what do you want to do, if you want to make a thread that connects the socket and then wait to be notified and want it to acquire the intrinsic lock of the object myLockObject to prevent interleaving then you have to put the code you want to be executed by the thread in a guarded block:
private final void connectSocket() {
synchronized(myLockObject) {
try {
mSocket.connect(null);
} catch (IOException e) {
}
try {
myLockObject.wait();
} catch (InterruptedException e) {
}
}
}
and in the connect method just call connectSocket
public void connect() {
new Thread(new Runnable() {
public void run() {
connectSocket();
}
}).start();
}

Java thread join method calls wait on which object?

I'm new to Java multi threading and little confused with how Java join and wait works.
I have the following example
public class Main {
private static int counter;
static class RunnableThread implements Runnable {
private static final String PREFIX = "RT-";
public RunnableThread() {
}
#Override
public void run() {
counter++;
System.out.println(PREFIX+counter);
try {
Thread.sleep(50000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Thread rt = new Thread(new RunnableThread());
//Thread tt = new TradThread();
rt.start();
//tt.start();
try {
rt.wait();
} catch (InterruptedException e1) {
System.out.println("Main thread wait is interrupted");
e1.printStackTrace();
}
System.out.println("MT-"+counter);
}
}
It throws IllegalMonitorStateException as the main thread doesn't hold any monitor. Now in the same code if I change rt.wait() to rt.join() it works.
When I see how join is implemented it looks like it calls the wait() method. Now how is the call to wait from inside the join valid?
I would assume The Main thread when it calls rt.join() the code in the join method is being executed by the Main thread itself.
Please help me to understand this.
Thanks
Thread.join() and Object.wait() are very different.
t.join()
Join current thread where you are behind thread t. So, current thread will not run until thread t finishes its work.
o.wait()
Release the lock of object o and pause current thread. So, current thread will not run until it obtains the lock of object o again by o.notify() or o.notifyAll() from other thread.
Note: you must have obtained the lock of object o before invoking this method.
Technically, in the join code, we have:
wait(0);
...
wait(delay);
in this case, this is the same as calling this.wait(). So to answer the question, the wait function being called is the object referenced by rt wait method.

Understanding wait() and notify() methods

I'm trying to understand how Java's wait and notify methods work. As per the documentation, wait() causes thread to wait for subsequent calls to notify() or notifyAll() methods but for some reason notify doesn't interrupt "waiting":
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
#Override
public void run() {
System.out.println("thread1 is started, waiting for notify()");
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
System.out.println(e.getLocalizedMessage());
}
}
System.out.println("waiting is over");
}
});
thread1.start();
// unblock thread1 in 2 seconds
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (thread1) {
thread1.notify();
}
}
You need to notify the object that is being waited on, not the thread that is waiting.
In your case the object waited on is an instance of an anonymous inner class, which is problematic because you cannot easily obtain a reference to it in order to notify it. You could solve this by extending Thread directly:
Thread thread1 = new Thread() {
#Override
public void run() {
System.out.println("thread1 is started, waiting for notify()");
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
System.out.println(e.getLocalizedMessage());
}
}
System.out.println("waiting is over");
}
};
Now the this (in synchronized (this)) refers to the thread itself, and the wait is called on the thread object too. In this case your current call to notify should be fine, since it notifies the same object (which happens in this case to be the thread that is waiting - but just to be clear, that need not be the case).
It isn't considered good practice to use an object for synchronisation that may also be used elsewhere; instances of Thread would be an example of this, and in fact the documentation specifically advises against it:
It is recommended that applications not use wait, notify, or notifyAll on Thread instances.
Also, you should correctly handle spurious wakeup; that is, wait may return because notify/notifyAll was called elsewhere or perhaps was not even called at all. As the documentation also says:
A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops [...]
Therefore, your example should really use a separate variable to track whether the wakeup was intentional (due to an explicit notify) or not.
for some reason notify doesn't interrupt "waiting":
#davmac's answer is correct but for posterity, there are some other ways you can do it because extending Thread and calling wait() and notify() on the Thread object is not recommended.
The best way would be to create a lock object. Making your lock objects final is always a good pattern although here it is also necessary to use it in the inner class.
final Object lock = new Object();
Thread thread1 = new Thread(new Runnable() {
...
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
// always a good pattern
Thread.currentThread().interrupt();
System.out.println(e.getLocalizedMessage());
}
}
...
}
...
synchronized (lock) {
lock.notify();
}
// might as well wait for it to finish
thread1.join();

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

Reason for IllegalMonitorStateException

I am getting an Illegal State exception for following code :
synchronized (this) {
try {
Thread.currentThread().wait();
notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
What i could made is synchronized on "this" will capture Monitor on Object calling the method and since i am calling wait on Current Thread object and i really don't have lock on that i am getting t error. Please validate my theory.
You call wait on the current thread, call it on this.
this.wait();
but then you will never get a notifyAll , because no thread that enters the synchronized block
can ever reach the notofyAll method. They all will wait for it first.
I guess you want one Thread to wait for another Thread to do some work.
Here is a short example of how synchronization between threads can work
public class ThreadTest {
public static void main(String[] args) throws InterruptedException {
Object monitor = new Object();
Thread t1 = new Thread(new R1(monitor));
Thread t2 = new Thread(new R2(monitor));
t1.start();
t2.start();
t2.join();
t1.join();
}
public static class R1 implements Runnable {
private Object monitor;
public R1(Object monitor) {
this.monitor = monitor;
}
public void run() {
System.out.println("R1 entered run");
synchronized (monitor) {
try {
monitor.wait();
System.out.println("R1 got monitor back");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static class R2 implements Runnable {
private Object monitor;
public R2(Object monitor) {
this.monitor = monitor;
}
public void run() {
System.out.println("R2 entered run");
synchronized (monitor) {
System.out.println("R2 will sleep for 1 sec");
try {
Thread.sleep(1000);
System.out
.println("R2 will notify all threads waiting for monitor");
monitor.notifyAll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
Output is:
R1 entered run
R2 entered run
R2 will sleep for 1 sec
R2 will notify all threads waiting for monitor
R1 got monitor back
You have acquired the lock of
this(current object)
and you are calling `
wait()
` on current thread that is why.
you should acquire lock before calling wait, notify notifyAll
Case1
...
synchronized(this){
this.wait();
}
...
Case2
...
synchronized(this){
Thread.currentThread.wait();
}
...
Case 1 is sensible code. It waits until another thread calls notify[All]() on "this" object.
Case 2 looks silly. It could only execute if the current thread and "this" were the same object, or you already had a lock on the current thread. Otherwise, you'd get IllegalMonitorStateException. Synchronising on Thread objects is a Bad Thing, because you can't be sure what else might be synchronising on them.
By the way, if what you want to do is just pause for a while in the program, you should sleep(), not wait().
From the Java doc for Object class wait() method:
IllegalMonitorStateException - if the current thread is not the owner
of the object's monitor.
In your code, current thread is the owner of the monitor of this and wait is called on Thread.currentThread.
Replace Thread.currentThread().wait(); with this.wait();

Categories

Resources