Java shared condition between classes throws IllegalMonitorStateException: null - java

I have structure something like this:
Lock wrapper - is used to store lock, condition and an object from response
public class LockWrapper{
private Lock lock;
private Condition myCondition;
private MyObject myObject;
public LockWrapper(Lock lock, Condition myCondition) {
this.lock = lock;
this.myCondition = myCondition;
}
public Condition getMyCondition() {
return myCondition;
}
public MyObject getMyObject() {
return myObject;
}
public void setObject(MyObject myObject) {
this.myObject = myObject;
}
public Lock getLock() {
return lock;
}
}
Task - pushed into a thread pool for execution. It initiates requests to a server and then waits for server responses.
public class MyTask implements Runnable{
private Lock lock = new ReentrantLock();
private Condition myCondition = lock.newCondition();
private MyWebSocketAPI api;
public MyTask(MyWebSocketAPI api) {
this.api = api;
}
#Override
public void run() {
lock.lock();
try {
// long randomLong = generateRandomLong();
api.sendRequest(randomLong, new LockWrapper(lock, myCondition));
myCondition.await();
//do something after we got a response
} finally{
lock.unlock();
}
}
}
WebSocket - gets requests and notifies tasks about responses
public abstract class MyWebSocketAPI extends WebSocketClient {
//...
private Map<Long, LockWrapper> lockWrappers = new ConcurrentHashMap<>();
public void sendRequest(Long id, LockWrapper lockWrapper){
this.lockWrappers.put(id, lockWrapper);
//processRequest
}
#Override
public void onMessage(String message) {
LockWrapper lockWrapper = lockWrappers.get(message.get(0).getAsLong());
lockWrapper.getLock().lock();
try{
lockWrapper.setMyObject(new MyObject(message));
this.lockWrappers.put(message.get(0).getAsLong(), lockWrapper);
lockWrapper.getMyCondition().signalAll();
} finally {
lockWrapper.getLock().unlock();
}
}
//...
}
Line lockWrapper.getMyCondition().signalAll(); throws an exception:
java.lang.IllegalMonitorStateException: null
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signalAll(AbstractQueuedSynchronizer.java:1954)
Why my conditions throw this exception when I try to notify tasks that we got their objects? Did I make a mistake somewhere or Java doesn't allow shared conditions?

It was my error in the Task. The problem was that I was creating Lock and Condition both global and local in method run. Lock and condition had the same name. In some cases I was using lock and in some cases this.lock (But it was two different locks). As a result, in method onMessage I had Condition and Lock which were not connected together.
After I removed duplicates everything works.

Related

Why am I getting IllegalMonitorStateException with this code?

I have 2 threads, one calls get() method, another put() method.
I need to synchronize this methods in order to see result of get only after put. I do know how to do this other way, but I want to understand why am i getting .IllegalMonitorStateException with this code.
public class TransferObject {
private int value;
protected volatile boolean isValuePresent = false; //use this variable
public synchronized int get() {
synchronized (TransferObject.class) {
System.out.println("Got: " + value);
notify();
}
return value;
}
public void put(int value) {
synchronized (TransferObject.class) {
this.value = value;
System.out.println("Put: " + value);
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Here is example of 2 threads.
public class ConsumerTask implements Runnable {
private TransferObject transferObject;
protected volatile boolean stopped;
public ConsumerTask(TransferObject transferObject) {
this.transferObject = transferObject;
new Thread(this, "ConsumerTask").start();
}
public void run() {
while (!stopped) {
transferObject.get();
}
}
public void stop() {
stopped = true;
}
}
public class ProducerTask implements Runnable {
private TransferObject transferObject;
protected volatile boolean stopped;
static volatile AtomicInteger i = new AtomicInteger(0);
public ProducerTask(TransferObject transferObject) {
this.transferObject = transferObject;
new Thread(this, "ProducerTask").start();
}
public void run() {
while (!stopped) {
transferObject.put(i.incrementAndGet());
}
}
public void stop() {
stopped = true;
}
}
You have two threads and one object for locking TransferObject.class.
When your thread ConsumerTask gets the lock, object TransferObject.class don't have sleeping threads, and when you call notify() for this monitor you get IllegalMonitorStateException
From the description for method notify:
Wakes up a single thread that is waiting on this object's monitor.
You don't have waiting treads for monitor TransferObject.class

Using this keyword as lock in concurrency

In the following program, does the this keywords in the LoggerThread class refer to LoggerThread object or LogService object? Logically it should refer to LogService in order for the syncronization to work, but semantically it seems it is referring to LoggerThread.
public class LogService {
private final BlockingQueue<String> queue;
private final LoggerThread loggerThread;
private final PrintWriter writer;
#GuardedBy("this") private boolean isShutdown;
#GuardedBy("this") private int reservations;
public void start() { loggerThread.start(); }
public void stop() {
synchronized (this) { isShutdown = true; }
loggerThread.interrupt();
}
public void log(String msg) throws InterruptedException {
synchronized (this) {
if (isShutdown)
throw new IllegalStateException("...");
++reservations;
}
queue.put(msg);
}
private class LoggerThread extends Thread {
public void run() {
try {
while (true) {
try {
synchronized (this) {
if (isShutdown && reservations == 0)
break;
}
String msg = queue.take();
synchronized (this) { --reservations; }
writer.println(msg);
} catch (InterruptedException e) { /* retry */ }
}
} finally {
writer.close();
}
}
}
}
Thank you for your help
this within LoggerThread methods refers to a LoggerThread instance.
LogService.this refers to the outer class.
Both isShutdown and reservations are synchronised by the different locks (LoggerThread.this and LogService.this), so #GuardedBy("this") doesn't reflect the reality.
This code is from the great book "Java Concurrency In Practice", Listing 7.15
It is a typo and is mentioned in "Errata" section:
http://jcip.net.s3-website-us-east-1.amazonaws.com/errata.html
this refers to the current instance of the immediately enclosing class. JLS #15.8.4.
Logically it should refer to LogService in order for the syncronization to work, but semantically it seems it is referring to LoggerThread.
Correct. It's a bug.

Correct wait to fetch queue of threads

Ok, so, I have a java class in which every method must run in a thread.
only one thread is executed per time and at a specific time.
I've implemented like this, with a inner class that extends Thread.
private class MyOperation extends Thread {
public static final String M1 = "method1";
public static final String M2 = "method2";
public static final String M3 = "method3";
protected long scheduledStartTime = 0;
private String type;
public MyOperation(String type, long milliSecondsToWait) {
this.type = type;
scheduledStartTime = System.currentTimeMillis() + mlliSecondsToWait;
}
#Override
public void run() {
switch(type){
case M1:
doMethod1();
break;
case M2:
doMethod3();
break;
case M3:
doMethod3();
break;
}
setCurrentOperation(null);
}
}
private void setCurrentOperation(MyOperation task) {
synchronized (currentOperation) {
this.currentOperation = task;
}
}
then I have the Thread queue and the current running thread
private MyOperation currentOperation;
private Queue <MyOperation> operationList;
And I'm fetching tasks like this:
private void fetchTasks() {
new Thread() {
#Override
public void run() {
while(true) {
if(currentOperation == null && !operationList.isEmpty()) {
currentOperation = getOperation();
while(currentOperation.scheduledStartTime > System.currentTimeMillis()) {
// do nothing, wait for proper time;
}
currentOperation.start();
}
}
}
}.start();
}
private MyOperation getOperation() {
synchronized (operationList) {
return operationList.remove();
}
}
and I'm adding thread to the queue like this, for example:
addOperation(new MyOperation(M1, 5));
private void addOperation(MyOperation task) {
synchronized (operationList) {
operationList.add(task);
}
}
My questions are:
Is there a better way to run each method in a diffent thread?
Is this way of fetching the threads queue correct?
Thank you very much
Just a little thing: if your operationsList is empty or the currentOperation is not null your thread starts going in circles really fast.
You could use Thread.wait() and .notify() to avoid this.
Also you are using currentOperation with and without synchronized. This could get you into trouble.
Have you condsidered using a ScheduledExecutorService (java.util.concurrent) to schedule your tasks?

static volatile boolean - thread not getting terminated

I wrote simple multithreaded application, just to play around with concurrency but I have a problem with boolean variable which controles the loop in thread. One of the functions should stop the thread if there's noelements left in queue and I guess that is my problem because If I add something in between braces to:
while (!queue.isEmpty()) {
}
isRunning = false;
So it becomes :
while (!queue.isEmpty()) {
System.out.println("ASD");
}
isRunning = false;
It is working a bit better - the program terminates after executing turnOff method
Any Ideas?
Here is full code of my app:
package test;
public class xxx {
public static void main(String[] args) {
Foo instance = Foo.getInstance();
Thread x = new Thread(instance);
x.start();
for (int count = 1; count < 100000; count++)
instance.addToQueue(count + "");
instance.turnOff();
}
}
And:
package test;
import java.util.LinkedList;
import java.util.List;
public class Foo implements Runnable {
private static Foo inner = null;
private static List<String> queue = new LinkedList<String>();
private volatile static boolean isRunning = false;
private Foo() { }
public static Foo getInstance() {
if (inner == null) {
inner = new Foo();
}
return inner;
}
public void addToQueue(String toPrint) {
synchronized (queue) {
queue.add(toPrint);
}
}
public void removeFromQueue(String toRemove) {
synchronized (queue) {
queue.remove(toRemove);
}
}
public void turnOff() {
while (!queue.isEmpty()) {
}
System.out.println("end");
isRunning = false;
}
#Override
public void run() {
isRunning = true;
while (isRunning) {
if (!queue.isEmpty()) {
String string = queue.get(0);
System.out.println(string);
removeFromQueue(string);
}
}
}
}
It is a race condition problem. Possibly the run method (the other thread) is executed after the turnOff in in the main thread so the flag isRunning is set as true again and the loop never ends.
That would explain why with a simple System.out.println("ASD") becomes better: the isRunning=false is delayed.
You have lots of problems in your code.
Busy loops in turnOff and wait
Unsynchronized access to queue in turnOff and run
Non-volatile, non-final access to inner
Needlessly static isRunning and queue variables
Race condition between turnOff and start invocations
Some of these are harmless in this specific instance (e.g. instance is always accessed from the main thread), but depending on your hardware configuration you are going to get bitten by some combination of the rest of them. The reason that adding the System.out "fixes" the problem is that it renders one of the busy loops less busy (fixes 1) and has an internal synchronization mechanism (fixes 2), but the others are still there.
I suggest getting rid of the isRunning variable and the test for queue.isEmpty() and replacing with a CountDownLatch.
package test;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
public class Foo implements Runnable {
private static final Foo inner = new Foo();
private final List<String> queue = new LinkedList<String>();
private final CountDownLatch latch = new CountDownLatch(1);
private Foo() { }
public static Foo getInstance() {
return inner;
}
public void addToQueue(String toPrint) {
synchronized (queue) {
queue.add(toPrint);
}
}
public void removeFromQueue(String toRemove) {
synchronized (queue) {
queue.remove(toRemove);
}
}
public boolean isEmpty() {
synchronized (queue) {
return queue.isEmpty();
}
}
public String getHead() {
synchronized (queue) {
return queue.get(0);
}
}
public void turnOff() throws InterruptedException {
latch.await();
System.out.println("end");
}
#Override
public void run() {
while (!isEmpty()) {
String string = getHead();
System.out.println(string);
removeFromQueue(string);
}
latch.countDown();
}
}
And the runner
package test;
public class XXX {
public static void main(String[] args) throws InterruptedException {
Foo instance = Foo.getInstance();
Thread x = new Thread(instance);
for (int count = 1; count < 100000; count++)
instance.addToQueue(count + "");
x.start();
instance.turnOff();
}
}
The main problem is the race condition between adding/removing elements and checking whether the queue is empty. In more words:
Wrapping add and remove calls in synchronized block provides you guarantees that all invocations of these methods will be performed sequentially. But, there is one more access to queue variable outside of synchronized block - it is queue.isEmpty(). It means there is a chance that some thread will get the result of this call and while it performs actions inside if block, other thread may add or remove elements.
This code also has some more concurrency problems, please let me know if you want them to be discussed (they are a little bit offtopic).
As Germann Arlington point, the value of queue.isEmpty() seems to be cached in the main thread. Try synchronize it:
while (true) {
synchronized(queue) {
if(queue.isEmpty())
break;
}
}
Or just make the queue to be volatile:
private volatile static List<String> queue = new LinkedList<String>();
This will solve your problem.
Use volatile variable isRunning in turnOff() method's while loop also.
public void turnOff() {
while (isRunning && !queue.isEmpty()) {
}
System.out.println("end");
isRunning = false;
}

Java method synchronization improper usage?

Suppose there is the following code:
class MyClass {
synchronized void myMethod1() {
//code
}
synchronized void myMethod2() {
//code
}
}
Now suppose myMethod1() and myMethod2() access distinct data; now if there are two threads, thread A calling only myMethod1() and thread B calling only myMethod2().
If thread A is executing myMethod1(), will thread B block waiting on myMethod2() even if they don't access the same data and there is no reason for this? As far as I know, synchronized methods use the monitor of this object for instance methods and that of MyClass.class object for static functions.
Your understanding of the situation is correct.
The typical solution is to have separate dedicated lock objects for the resources in question.
class MyClass {
private final Lock lock1 = new ReentrantLock();
private final Lock lock2 = new ReentrantLock();
void myMethod1() {
lock1.lock();
try {
//code
} finally {
lock1.unlock();
}
}
void myMethod2() {
lock2.lock();
try {
//code
} finally {
lock2.unlock();
}
}
}
You are correct in all your suppositions. In the case where no data is in common then there is no reason to synchronize at the method level.
The sychronized method will lock on the object itself. So each method will have to wait for the other to finish its access to release the object. If your methods are truly accessing distinct data you can do something like this:
class MyClass {
private static Object mLock1 = new Object();
private static Object mLock2 = new Object();
void myMethod1() {
synchronized(mLock1) {
//code
}
}
void myMethod2() {
synchronized(mLock2) {
//code
}
}
}
And you can then access them independently.
edit: You can essentially think of synchronized methods as being equivalent to this:
void myMethod1() {
synchronized(this) {
//your code
}
}
Shown like this it is pretty clear why two synchronized methods block each other because they have to wait for the lock on this to free.
Yes, declaring both methods as synchronized will make them block each other, even if they access different data elements.
To avoid this, you can use a more fine grained locks. E.g.:
class MyClass {
private static final Object lock1 = new Object();
private static final Object lock2 = new Object();
void myMethod1() {
synchronized (lock1) {
//code
}
}
void myMethod2() {
synchronized (lock2) {
//code
}
}
You can use different monitors for myMethod1 and myMethod2 as follows:
class MyClass {
Object monitor1 = new Object();
Object monitor2 = new Object();
void myMethod1() {
synchornized(monitor1) {
//code
}
}
void myMethod2() {
synchronized(monitor2) {
//code
}
}
}

Categories

Resources