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();
Related
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..
I have the following simple code in which I put and take from a Queue represented as an ArrayList.
public class EmailService {
private Queue<Email> emailQueue;
private Object lock;
private volatile boolean run;
private Thread thread;
public void sendNotificationEmail(Email email) throws InterruptedException {
emailQueue.add(email);
synchronized (lock) {
lock.notify();
lock.wait();
}
}
public EmailService() {
lock = new Object();
emailQueue = new Queue<>();
run = true;
thread = new Thread(new Runnable() {
#Override
public void run() {
while (run) {
System.out.println("ruuuning");
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
if (emailQueue.getSize() > 0) {
sendEmail(emailQueue.poll());
}
lock.notify();
}
}
}
private void sendEmail(Email email) {
System.out.println("Sent email from " + email.getFrom() + " to " + email.getTo() + " with content: " + email.getContent());
}
});
thread.start();
}
public void close() throws InterruptedException {
run = false;
synchronized (lock) {
lock.notify();
System.out.println("Thread will join " + thread.isInterrupted());
thread.join();
System.out.println("Thread after join");
}
}
}
I don't understand why my thread is blocked in join() method.
From main I call as follow:
eService = new EmailService();
Email e1 = new Email(client1, client2, "content1");
eService.sendNotificationEmail(e1);
eService.close();
Without running it...
The close() method holds lock at the time it calls thread.join() and waits on thread (forever)
thread is waiting to reacquire lock so cannot run
Both are now waiting on each other, this is a deadlock. Try moving the Thread.join() after the synchronized block:
public void close() throws InterruptedException {
run = false;
synchronized (lock) {
lock.notify();
System.out.println("Thread will join " + thread.isInterrupted());
}
thread.join();
System.out.println("Thread after join");
}
#drekbour explained how your program could hang in the join() call, but FYI: Here's a different way that your program could hang. This is called lost notification.
Your main thread creates a new EmailService instance. The new instance creates its thread and calls thread.start() *BUT* it could take some time for the thread to actually start running. Meanwhile...
Your main thread creates a new Email instance, and calls eService.sendNotificationEmail(...). That function adds the new message to the queue, locks the lock, notifies the lock, and then waits on the lock.
Finally, The service thread starts up, enters its run() method, locks the lock, and then it calls lock.wait().
At this point, the program will be stuck because each thread is waiting to be notified by the other.
The way to avoid lost notification is, in the consumer thread, do not call wait() if the thing that you are waiting for already has happened.
synchronized(lock) {
while (theThingHasNotHappenedYet()) {
lock.wait();
}
dealWithTheThing();
}
In the producer thread:
synchronized(lock) {
makeTheThingHappen();
lock.notify();
}
Notice how both threads lock the lock. Ever wonder why lock.wait() throws an exception if the lock isn't locked? The examples above illustrate why. The lock prevents the producer thread from making the thing happen after the consumer already has decided to wait. That is key: If the consumer were to wait after the producer calls notify() then it's game over. The program hangs.
Suppose I have one thread named T1 which is holding the lock while other threads T2, T3, T4 are waiting for the lock. Now, I want to stop thread T2, but the other threads T3, T4 should be still waiting. How could I achieve this?
You can use the interrupt() method from the Thread Class something like this
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(someTask());
t.start();
Thread.sleep(3_000);
t.interrupt();
t.join(1_000);
}
private static Runnable someTask() {
return () -> {
for (int i = 0; i < 10; i++) {
System.out.print(i);
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
break;
}
}
};
}
What you should do is utilize T2.interrupt(). Interrupt will wake up the respective thread and throw an InterruptionException that the thread must handle. From here, you can end the thread. Lets look at a brief example of T2's possible Runnable's run() method below.
public void run() {
while (true) {
try {
doNonBlockingWork(); // Random code logic
doBlockingWork(); // Where the thread will attempt to get and wait for the lock
doMoreCode(); // Will never get here if interrupt is called while waiting for lock above
} catch (InterruptedException e){
Thread.currentThread().interrupt(); // Maintain Interrupt Status
break; // Finish
}
}
}
If another thread, lets say the main thread executes the following code,
public void killSpecificThread() {
doMyLogic();
startThreads(); // All the threads begin
T2.interrupt();
doMoreLogic();
}
T2 will wake up (this works the same as well if it was awake, just no wake up step) and immediately be thrown an InterruptionException. Because of our try catch above, we are able to handle it by finishing the run() method.
I have simple code:
public class testing {
private static Object objToSync = new Object();
public static void main(String[] args) {
String obj1 = null;
synchronized(objToSync){
System.out.println("something one");
doSomething();
System.out.println("something three ");
}
doSomething();
}
private static void doSomething() {
synchronized(objToSync){
System.out.println("something two");
}
}
I have read several things but still getting confused with this one. Why does the doSomething in the main gets called? Is it not suppose to wait till the synchronized object gets unlocked? Sorry if I am sounding stupid, i am just confused.
Is it not suppose to wait till the synchronized object gets unlocked?
The lock is held by the thread, so the fact that you're synchronizing on it twice (in the case of the first call to doSomething in main) doesn't matter, it's on the same thread. If another thread then tried to enter a synchronized block on objToSync, that other thread would wait until this thread released all of its locks.
Your code will do this:
Enter main
Get a lock for the current thread on the objToSync object
Output "something one"
Call doSomething
Get a second lock for the current thread on objToSync
Output "something two"
Release the second lock for the current thread on objToSync
Return from doSomething
Output "something three"
Release the first lock for the current thread on objToSync
Call doSomething
Acquire a new lock (for that same thread) on objToSync
Output "something two"
Release that lock
Return from doSomething
Return from main
Here's an example using two threads:
public class SyncExample {
private static Object objToSync = new Object();
public static final void main(String[] args) {
Thread second;
System.out.println("Main thread acquiring lock");
synchronized (objToSync) {
System.out.println("Main thread has lock, spawning second thread");
second = new Thread(new MyRunnable());
second.start();
System.out.println("Main thread has started second thread, sleeping a moment");
try {
Thread.currentThread().sleep(250);
}
catch (Exception e) {
}
System.out.println("Main thread releasing lock");
}
System.out.println("Main thread sleeping again");
try {
Thread.currentThread().sleep(250);
}
catch (Exception e) {
}
System.out.println("Main thread waiting for second thread to complete");
try {
second.join();
}
catch (Exception e) {
}
System.out.println("Main thread exiting");
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("Second thread running, acquiring lock");
synchronized (objToSync) {
System.out.println("Second thread has lock, sleeping a moment");
try {
Thread.currentThread().sleep(250);
}
catch (Exception e) {
}
System.out.println("Second thread releasing lock");
}
System.out.println("Second thread is done");
}
}
}
Output:
Main thread acquiring lock
Main thread has lock, spawning second thread
Main thread has started second thread, sleeping a moment
Second thread running, acquiring lock
Main thread releasing lock
Main thread sleeping again
Second thread has lock, sleeping a moment
Main thread waiting for second thread to complete
Second thread releasing lock
Second thread is done
Main thread exiting
Locks are reentrant so if some thread posses lock it can enter other synchronized blocks based on that lock. In your case you have only one thread (main) and he is doing something like this
synchronized(objToSync){
System.out.println("something one");
synchronized(objToSync){
System.out.println("something two");
}
System.out.println("something three");
}
Locks are reentrants for the same thread. That means a thread which has gained the lock of an object can access this and any other synchronized methods (or atomic statements, like here in your example) of the object. This thread will not need to gain the lock again, once it has gotten it.
Thats because your program has only 1 thread- the main thread.
Why may this happen? The thing is that monitor object is not null for sure, but still we get this exception quite often:
java.lang.IllegalMonitorStateException: (m=null) Failed to get monitor for (tIdx=60)
at java.lang.Object.wait(Object.java:474)
at ...
The code that provokes this is a simple pool solution:
public Object takeObject() {
Object obj = internalTakeObject();
while (obj == null) {
try {
available.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
obj = internalTakeObject();
}
return obj;
}
private Object internalTakeObject() {
Object obj = null;
synchronized (available) {
if (available.size() > 0) {
obj = available.keySet().iterator().next();
available.remove(obj);
synchronized (taken) {
taken.put(obj, Boolean.valueOf(true));
}
}
}
return obj;
}
public void returnObject(Object obj) {
synchronized (taken) {
taken.remove(obj);
}
synchronized (available) {
if (available.size() < size) {
available.put(obj, Boolean.valueOf(true));
available.notify();
}
}
}
Am I missing something?
EDIT: The exception happens in available.wait(); line.
See the javadoc for Object.wait.
in particular "The current thread must own this object's monitor." and "[throws] IllegalMonitorStateException - if the current thread is not the owner of the object's monitor." That is, you need to synchronize on the object you are going to call wait on.
so your code should be:
synchronized (available) {
available.wait();
}
available.wait(); must be in a synchronized(available) section
You are getting the "IllegalMonitorStateException" from
available.wait()
because the current thread that invokes the wait() method is not the owner of the Object's monitor that is
referenced by the "available" object reference.
For a thread to become the owner of an object's monitor, there are 3 ways.
By executing a synchronized instance method of that object.
By executing the body of a synchronized block that synchronizes on the object.
For objects of type Class by executing a synchronized static method of that class.
Simple sample code for each scenario. All three code snippets are separate classes for each type, just copy the code and run it. I added comments heavily into the code to explain what's happening in each case. If it's too many comments for you. just delete them to make the code more concise.
Also, read the code in main() method first to get an idea about threadOne and threadTwo first.
By executing a synchronized instance method of that object.
import static java.lang.System.out;
public class SynchronizedInstanceMethodClass {
synchronized void synchronizedInstanceMethod() { // threadOne acquire the monitor for "this" and continue.
try {
out.println("EVENT #1 threadOne is about to strat waiting on the "
+"monitor it already has - [\"this\"]....");
this.wait(); // The threadOne already have the monitor for "this",
// just release the monitor and go and wait threadOne.
out.println("EVENT #3 Notify received and continue execution...");
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
synchronized void notifierForAllThreads() { // threadTwo acquire the monitor for "this",
// which was released by threadOne when it went to waiting and contine.
out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
+" waiting on the monitor of -[\"this\"]....");
this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all
// threads waiting on "this" and releases the monitor
}
public static void main(String [] args) {
SynchronizedInstanceMethodClass mc = new SynchronizedInstanceMethodClass();
Thread threadOne = new Thread(() -> {mc.synchronizedInstanceMethod();});
Thread threadTwo = new Thread(() -> {mc.notifierForAllThreads();});
threadOne.start(); // Start the waiting of Thread one
threadTwo.start(); // Notify the waiting threadOne
}
}
By executing the body of a synchronized block that synchronizes on the object.
import static java.lang.System.out;
public class SynchronizedBlockClass {
void synchronizedBlockInstanceMethod() {
synchronized (this) { // threadOne acquire the monitor for "this" and continue.
try {
out.println("EVENT #1 threadOne is about to strat waiting on the "
+"monitor it already has - [\"this\"]....");
this.wait(); // The threadOne already have the monitor for "this",
// just release the monitor and go and wait threadOne.
out.println("EVENT #3 Notify received and continue execution...");
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
}
void synchronizedBlockNotifierForAllThreads() {
synchronized (this) { // threadTwo acquire the monitor for "this",
// which was released by threadOne when it went to waiting and continue.
out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
+" waiting on the monitor of -[\"this\"]....");
this.notifyAll(); // threadTwo who owns the monitor on "this" notifies all
// threads waiting on "this" and releases the monitor
}
}
public static void main(String [] args) {
SynchronizedBlockClass mc = new SynchronizedBlockClass();
Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
threadOne.start(); // Start the waiting of Thread one
threadTwo.start(); // Notify the waiting threadOne
}
}
For objects of type Class by executing a synchronized static method of that class.
import static java.lang.System.out;
public class StaticClassReferenceClass {
void synchronizedBlockInstanceMethod() {
synchronized (StaticClassReferenceClass.class) { // threadOne acquire the monitor for class literal and continue.
try {
out.println("EVENT #1 threadOne is about to strat waiting on the "
+"monitor it already has - [StaticClassReferenceClass.class]....");
StaticClassReferenceClass.class.wait(); // The threadOne already have the monitor for the class literal,
// So it just release the monitor and go and wait.
out.println("EVENT #3 Notify received and continue execution...");
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
}
}
void synchronizedBlockNotifierForAllThreads() {
synchronized (StaticClassReferenceClass.class) { // threadTwo acquire the monitor for the class literal,
// which was released by threadOne when it went to waiting.
out.println("EVENT #2 threadTwo is about to notify all threads(including threadOne) "
+" waiting on the monitor of -[StaticClassReferenceClass.class]....");
StaticClassReferenceClass.class.notifyAll(); // threadTwo who owns the monitor on the class literal notifies all
// threads waiting on it and releases the monitor
}
}
public static void main(String [] args) {
StaticClassReferenceClass mc = new StaticClassReferenceClass();
Thread threadOne = new Thread(() -> {mc.synchronizedBlockInstanceMethod();});
Thread threadTwo = new Thread(() -> {mc.synchronizedBlockNotifierForAllThreads();});
threadOne.start(); // Start the waiting of Thread one
threadTwo.start(); // Notify the waiting threadOne
}
}
takeObject() method must be synchronized or, we have to write synchronized block inside this method. I hope u should get compile time exception for this.