Please explain to me why my code throws a IllegalMonitorStateException at the wait function, as far as I know this only happens if its not done in a synchronized part?
private void deliver(int target) {
Warehouse targetW = targets[target];
targetW.deliver();
System.out.println(name + " starts to deliver too " +
targetW.getName());
int sleepTime = DELIVERY_TIME / LOADING_CAPACITY;
int counter = 0;
while (counter < LOADING_CAPACITY) {
synchronized (targetW) {
while (!targetW.fill(1)) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
counter++;
try {
sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
leaveMSG(targetW);
targetW.delivered();
}
You can only call wait() inside a synchronized block on that object.
Inside synchronized (targetW), you can call targetW.wait().
Related
I created two separate threads one for writing into a list and second for removing from the list.
package com.produ.consu;
public class Test {
public static void main(String[] args) {
Operations operations = new Operations();
Runnable r1 = new ThreadsClass(operations);
Runnable r2 = new ThreadsClass(operations);
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.setName("READ");
t2.setName("WRITE");
t1.start();
t2.start();
}
}
Above is Test class where I created threads.
package com.produ.consu;
public class ThreadsClass implements Runnable {
Operations operations;
ThreadsClass(Operations operations){
this.operations=operations;
}
#Override
public void run() {
// TODO Auto-generated method stub
if(Thread.currentThread().getName().equals("WRITE")) {
operations.writeList();
}
else {
operations.readList();
}
}
}
Above is class calling synchronized methods based on the thread name:
import java.util.ArrayList;
import java.util.List;
public class Operations {
List<Integer> list=null;
int count=0;
boolean flag;
Operations(){
list=new ArrayList<>();
flag=true;
}
public synchronized void writeList() {
// TODO Auto-generated method stub
while(true) {
if(flag) {
count++;
list.add(count);
System.out.println("inise if block...."+Thread.currentThread().getName());
System.out.println(list);
flag=false;
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else {
notify();
}
}
}
public synchronized void readList() {
// TODO Auto-generated method stub
while(true) {
if(!flag) {
Integer i = list.remove(0);
System.out.println(i+"..removed at index by"+Thread.currentThread().getName());
flag=true;
notify();
}
else {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Above is where I mentioned functionality.
So write thread hast to write element to list and wait until it is removed by the second thread.
Once removed second should notify 1st and wait for until element inserted.
But getting...
inise if block....WRITE [1]
Not even removed and it has to be a continuous process.
Give me suggestions on given code.
You should wait() inside the else block also, otherwise the while will continue to run if the if is not satisfied and the other thread won't get a chance to execute.
After the read/write operation is performed the thread should call notify to wake up the other thread and itself should go in the waiting state.
public synchronized void writeList() {
while (true) {
if (flag) {
count++;
list.add(count);
System.out.println("inise if block...." + Thread.currentThread().getName());
System.out.println(list);
flag = false;
try {
notify(); //notify the read thread that write is complete
wait(); // go into the waiting state so that no further write is done until the current element is removed by the read thread.
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
wait(); //wait in else, otherwise while will run endlessly
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public synchronized void readList() {
while (true) {
System.out.println("in read");
if (!flag) {
Integer i = list.remove(0);
System.out.println(i + "..removed at index by" + Thread.currentThread().getName());
flag = true;
try {
notify(); //notify write thread that read is complete
wait(); //go into wait until new element is inserted
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
try {
wait(); //wait in else otherwise while runs endlessly
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
You should replace the method synchronization with more granular synchronization: wrap the operations that access the list and update count with a synchronized block.
Alternatively, use a linked blocking queue to pass “messages” between threads (or, in more advanced scenarios, a messaging solution such as Akka, Kafka, zeromq, or other similar solutions)
Since you only add one elemet at a time you could also use a Exchanger.
Take a look at the Java concurrent package.
import java.io.IOException;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class Foo {
public static void main(String[] args) throws IOException, InterruptedException {
final Exchanger<Integer> exchanger = new Exchanger<>();
ExecutorService executorService = Executors.newCachedThreadPool();
executorService.execute(() -> {
// producer
int count = 0;
while (!Thread.currentThread().isInterrupted()) {
try {
exchanger.exchange(count++);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
executorService.execute(() -> {
// reader
while (!Thread.currentThread().isInterrupted()) {
try {
System.out.println("consume " + exchanger.exchange(null));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
System.in.read();
executorService.shutdownNow();
executorService.awaitTermination(10, TimeUnit.SECONDS);
System.out.println("Shut down");
}
}
Thread faculty = new Thread(() -> {
try {
while (true) {
boolean is_grab = false;
semp.acquire();
if (candy > 0) {
System.out.println("No." + NO + " faculty grabs a candy");
candy--;
is_grab = true;
System.out.println("Candy num left:" + candy);
}
semp.release();
if (is_grab) {
Thread.sleep(1000);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
faculty.start();
}
In the code above, I use a semaphore implementation for synchronization and
if (is_grab) { Thread.sleep(1000); } could be executed.
However, in code below,
Thread faculty = new Thread(() -> {
synchronized (Bowl.class) {
while (true) {
while (Bowl.candy <= 0) {
try {
Bowl.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("No." + NO + " faculty grabs a candy");
Bowl.candy--;
System.out.println("Candy num left:" + Bowl.candy);
Bowl.class.notifyAll();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
I use synchronized on Bowl.class but try{sleep} is unreachable. Why?
In the lower example, there is no break statement to get out of the while(true) loop.
A project source code has a Java method for SQL handling. The method does work, but it uses a questionable workaround: try-catch block at the very end of the method for normal execution. What is the correct way to implement it?
public void run() {
if (running) {
return;
}
running = true;
while(null == Common.server || null == Common.database || !ConnectionsPool.isInitialized()) {
// Wait until the database is set before continuing...
try {
Thread.sleep(1000);
}
catch(Exception ex) {}
}
while(running) {
final Connections cs = ConnectionsPool.getConnections();
Connection c = null;
while(!entries.isEmpty()) {
if (null == c) {
c = cs.getConnection();
}
SQLLogEntry entry = entries.remove();
if (null != entry) {
try {
write(entry, c); //find usages
}
catch (SQLException ex) {
writeLogFile("Could not write entry to SQL", ex);
}
}
}
if (null != c) {
try {
c.commit();
}
catch (SQLException ex) {
writeLogFile("Could commit to SQL", ex);
try {
c.rollback();
}
catch (SQLException ex1) {
}
// log
final StringWriter err = new StringWriter();
ex.printStackTrace(new PrintWriter(err));
EditorTransactionUtil.writeLogFile(err.toString());
// for user
final String msg = "Exception: " + EditorUtil.getErrorMessage(ex.getMessage());
try {
SwingUtilities.invokeAndWait(() -> {
JOptionPane.showMessageDialog(null, msg);
});
}
catch (Throwable ex1) {
}
}
finally {
cs.returnConnection(c);
}
c = null;
}
synchronized(entries) {
try {
entries.wait(1000);
}
catch (InterruptedException ex) {
// This is a workaround to process this loop...
}
}
}
writeLogFile("SQLMsgLogger run loop stopping...");
}
Problems with this code start here.
If(running) return;
running=true;
This is clearly an attempt to make sure that only one thread executes. This is a wrong way to check concurrency. Second tread might kick in right when if check ended, but assignment didn't start yet. You need to use syncronizible interface.
As for the disposed try catch block - as Konrad pointed out it will not be executed without Thread.interrupt() call. It might be dead code left from previous versions.
I'm taking one Integer variable and sharing with two threads. One thread should print even numbers and one thread should print odd number sequentially.
But notify() throwing IllegalMonitorStateException.
package mywaitnotifytest;
public class App {
public static void main(String[] args) {
Integer i=0;
Even even = new Even(i);
even.setName("EvenThread");
Odd odd = new Odd(i);
odd.setName("OddThread");
even.start();
odd.start();
}
}
class Even extends Thread{
Integer var;
Even(Integer var){
this.var=var;
}
#Override
public void run() {
while(true){
synchronized (var) {
if(var%2==0){
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var++;
System.out.println(Thread.currentThread().getName()+" "+var);
var.notify();
}
}
}
}
class Odd extends Thread{
Integer var;
Odd(Integer var){
this.var=var;
}
#Override
public void run() {
while(true){
synchronized (var) {
if(var%2!=0){
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var++;
System.out.println(Thread.currentThread().getName()+" "+var);
var.notify();
}
}
}
}
And the output is :
OddThread 1
Exception in thread "OddThread" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at mywaitnotifytest.Odd.run(App.java:67)
I think this is sufficiently different to the usual answer to give another one.
In this case you are using synchronized. When you apply a lock it is on a object not a reference.
synchronized (var) {
This locks the object var references, not on var as a field.
var++;
This replaces the object var points to. It is the same as
var = Integer.valueOf(var.intValue() + 1);
Note: Integer and indeed all the primitive wrappers are Immutable. When you perform any operation on them you are actually unboxing, calculating using the primitive value and re-boxing the object. It is possible to get the same object back if it is pooled. e.g.
Integer i = 10;
i += 0; // gives back the same object.
However, if the object is not pooled
Double d = 10;
d += 0; // creates a new object.
var.notify();
Attempts the call notify on the new object, not the one which was locked.
You shouldn't attempt to lock a field which you mutate. It won't do what it appears to do. You also shouldn't lock on a pooled object. In this case you could have another thread using the same Integer for an unrelated purpose and notify() will wake up an unrelated thread.
To use wait/notify correctly, you should
notify() or notifyAll() after a state change in another shared field.
you should use a while loop for wait() to check the state change.
If you don't do this
notify can be lost if another thread is not waiting.
wait can wake spuriously, even when no notify was called.
For the above requirement what is the edit suggested in the code? How do i share the same object for multiple threads?
public class PingPong implements Runnable {
static class Shared { int num; }
private final Shared var;
private final int bit;
public static void main(String[] args) {
Shared var = new Shared();
new Thread(new PingPong(var, 0), "EvenThread").start();
new Thread(new PingPong(var, 1), "OddThread").start();
}
PingPong(Shared var, int bit) {
this.var = var;
this.bit = bit;
}
#Override
public void run() {
try {
String name = Thread.currentThread().getName();
while (true) {
synchronized (var) {
while (var.num % 2 == bit)
var.wait();
var.num++;
System.out.println(name + " " + var.num);
var.notify();
}
}
} catch (InterruptedException e) {
System.out.println("Interrupted");
}
}
}
Instead of using Integer wrapper class,I created my own class and now It works fine.
package mywaitnotifytest;
public class App {
public static void main(String[] args) {
MyInt i = new MyInt(0);
Even even = new Even(i);
even.setName("EvenThread");
Odd odd = new Odd(i);
odd.setName("OddThread");
even.start();
odd.start();
}
}
class Even extends Thread {
MyInt var;
Even(MyInt var) {
this.var = var;
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(200);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (var) {
if (var.i % 2 == 0) {
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var.i++;
System.out.println(Thread.currentThread().getName() + " " + var.i);
var.notify();
}
}
}
}
class Odd extends Thread {
MyInt var;
Odd(MyInt var) {
this.var = var;
}
#Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
synchronized (var) {
if (var.i % 2 != 0) {
try {
var.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
var.i++;
System.out.println(Thread.currentThread().getName() + " " + var.i);
var.notify();
}
}
}
}
class MyInt {
int i = 0;
public MyInt(int i) {
super();
this.i = i;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "" + i;
}
}
The below program is supposed to print even and odd numbers by two different threads but I am getting illegal monitor exception on notify method in the below code :
public class oddeven {
static volatile Integer t = 0;
public static void main(String as[]) {
oddrunnable or = new oddrunnable(t);
evenrunnable er = new evenrunnable(t);
Thread t1 = new Thread(or, "odd");
Thread t2 = new Thread(er, "even");
t1.start();
t2.start();
}
}
class oddrunnable implements Runnable {
Integer t;
public oddrunnable(Integer t) {
this.t = t;
}
#Override
public void run() {
// TODO Auto-generated method stub
synchronized (t) {
while (true) {
if (t % 2 == 0) {
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Current thread id " + Thread.currentThread().getName());
t++;
t.notify();
}
}
}
}
class evenrunnable implements Runnable {
Integer t;
public evenrunnable(Integer t) {
this.t = t;
}
#Override
public void run() {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
synchronized (t) {
while (true) {
if (t % 2 != 0) {
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Current thread id " + Thread.currentThread().getName());
t++;
t.notify(); // <-------------------exception on this line
}
}
}
}
the notify method is called on the synchronized object itself. Not sure why this is coming :
Current thread id even
Exception in thread "even" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at evenrunnable.run(oddeven.java:86)
at java.lang.Thread.run(Thread.java:619)
Integers in java wrapper are immutable, so as soon as you do t++, you are going to assign a new Integer object which you didn't took lock against and hence you get IllegalMonitorStateException.
Instead of Integer, use AtomicInteger and then use incrementAndGet api to increment the value of counter.
The problem is in using Integer object for synchronization and than doing increment(++) operation on it. I think its creating new integer object and than all the synchronized logic is going for toss. I am not sure about it as while debugging your code, eclipse was not showing whether it created new object.
A better alternative is to use some wrapper object around your integer or AtomicInteger class. Here is your code with AtomicInteger class used
public class oddeven {
static volatile AtomicInteger t = new AtomicInteger(0);
public static void main(String as[]) {
oddrunnable or = new oddrunnable(t);
evenrunnable er = new evenrunnable(t);
Thread t1 = new Thread(or, "odd");
Thread t2 = new Thread(er, "even");
t1.start();
t2.start();
}
}
class oddrunnable implements Runnable {
AtomicInteger t;
public oddrunnable(AtomicInteger t) {
this.t = t;
}
#Override
public void run() {
// TODO Auto-generated method stub
synchronized (t) {
while (true) {
if (t.intValue() % 2 == 0) {
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Current thread id " + Thread.currentThread().getName());
t.incrementAndGet();
t.notify();
}
}
}
}
class evenrunnable implements Runnable {
AtomicInteger t;
public evenrunnable(AtomicInteger t) {
this.t = t;
}
#Override
public void run() {
// TODO Auto-generated method stub
// TODO Auto-generated method stub
synchronized (t) {
while (true) {
if (t.intValue() % 2 != 0) {
try {
t.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Current thread id " + Thread.currentThread().getName());
t.incrementAndGet();
t.notify(); // <-------------------exception on this line
}
}
}
}