I assume you were confused by the wait()
method name, thinking it may allow you to wait until exec()
is finished, but really it’s not and has completely different purpose.
What I believe you wanted here is to call Process.waitFor()
method:
try {
Runtime runtime = Runtime.getRuntime();
String cmd = new String(C:\abc.bat);
process = runtime.exec(""" + cmd + """);
process.waitFor();
} catch (Exception e) {
e.printStackTrace();
}
which should do what you may originally expected — to wait until batch execution is finished.
On the other hand, wait()
method in Java (which comes from Object.wait()
) is related to multi-threading programming and to Java implementation of the monitor thread synchronization concept. Historically, it was put to the main Object.java
class, so all classes inherit it and that’s what confusion may come from.
In your example it’s definitely not the right method to call. And the IllegalStateMonitor
exception message you’re getting:
current thread is not owner
tries to give you an implicit hint on threads synchronization issue.
Though again, when you’re not using multi-threading in your code it may confuse you a lot and doesn’t provide any clue what could go wrong, as you not expecting it.
wait()
method should only be called on the monitor objects, when you’re writing code inside of synchronized blocks or methods, e.g.:
private final List<Task> tasks = new ArraList<>();
private synchronized void waitForTasks() throws InterruptedException {
// because 'synchronized' word used on method,
// here monitor is the whole class, i.e. 'this'
if (tasks.isEmpty()) {
wait(); // method is called on the class itself, as it's the monitor object
}
doTasks();
}
or:
private final List<Task> tasks = new ArraList<>();
private void waitForTasks() throws InterruptedException {
synchronized (tasks) { // monitor object is set to 'tasks' object
if (tasks.isEmpty()) {
tasks.wait(); // method is called on the monitor
}
doTasks();
}
}
If you would like to get more information on monitor concept in Java, you can this nice article on the topic.
In this tutorial, we will learn IllegalMonitorStateException and when it is thrown with examples. We will also see how we can prevent our code from throwing this exception along with some of the best practices to follow in multithreaded applications.
- 1. Java IllegalMonitorStateException class
- 2. What causes IllegalMonitorStateException
- 3. Resolving IllegalMonitorStateException
- 4. Best Practices
- 5. Conclusion
IllegalMonitorStateException class present in java.lang package and has been there since Java version 1.0. It extends RuntimeException class; hence, it’s an unchecked exception and needs not to be declared in a method’s or a constructor’s throws clause.
Constructors defined in this class:
IllegalMonitorStateException():
Creates an instance of the IllegalMonitorStateException class, setting null as its message.IllegalMonitorStateException(String message):
Creates an instance of the IllegalMonitorStateException class, using the specified message.
2. What causes IllegalMonitorStateException
For inter-thread communication (in which 2 threads communicate with each other), threads have to use wait()
, notify()
and notifyAll()
methods. Thread class inherits these methods from the Object class.
A Thread should acquire the object’s lock to call these methods on that object. If a Thread tries to call wait(),
notify()
and notifyAll()
methods on an object without acquiring that object’s lock or outside of the synchronized block, the program throws IllegalMonitorStateException.
Let’s now look at an example of how a Thread raises IllegalMonitorStateException. In this example, we are going to create a Waiting Thread and a Notifying Thread.
- WaitingThread calls the
wait()
method and enters into a waiting state until some other Thread callsnotify()
method and notifies it. - NotifyingThread calls the
notify()
method and notifies the waiting Thread to start processing again.
public class IllegalMonitorStateExceptionDemo
{
//This object is used for synchronization among threads.
public final static Object obj = new Object();
public static class WaitingThread extends Thread {
@Override
public void run() {
try {
//Calling wait() method outside of synchronized area
obj.wait(); // Raises IllegalMonitorStateException
}
catch (InterruptedException ex) {
System.out.println(Thread.currentThread().getName() + " gets Interrupted");
}
}
}
public static class NotifyingThread extends Thread {
@Override
public void run() {
try {
// Thread sleep for 5 sec
Thread.sleep(5000);
// Calling notify() outside of synchronized area
obj.notify(); // Raises IllegalMonitorStateException
}
catch (InterruptedException ex) {
System.err.println(Thread.currentThread().getName() + " gets Interrupted");
}
}
}
}
Try running both threads to verify.
public static void main(String[] args) {
WaitingThread waitingThread = new WaitingThread();
NotifyingThread notifyingThread = new NotifyingThread();
waitingThread.start();
notifyingThread.start();
}
We will get the IllegalMonitorStateException in the console.
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Object.wait(Object.java:338)
at com.howtodoinjava.concurrency.IllegalMonitorStateExceptionDemo $WaitingThread.run(IllegalMonitorStateExceptionDemo.java:23)
Exception in thread "Thread-1" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.notify(Native Method)
at com.howtodoinjava.concurrency.IllegalMonitorStateExceptionDemo $NotifyingThread.run(IllegalMonitorStateExceptionDemo.java:39)
3. Resolving IllegalMonitorStateException
IllegalMonitorStateException resolves when a Thread calls wait()
, notify()
and notifyAll()
methods on an object after acquiring that object’s lock means it should call these methods inside synchronized
block only.
In the above example, if both Waiting & Notifying Threads call wait()
and notify()
in synchronized block then we won’t get IllegalMonitorStateException in our code.
So the correct way of calling these methods without this exception is as below,
public static class WaitingThread extends Thread {
@Override
public void run() {
try {
//Obtain lock using the synchronized keyword
synchronized(obj){
//Calling wait() inside synchronized block
obj.wait();
}
}
catch (InterruptedException ex) {
System.err.println(Thread.currentThread().getName() + " gets Interrupted");
}
}
}
public static class NotifyingThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(5000);
//Obtain lock first
synchronized(obj){
//Calling notify() inside synchronized block
obj.notify();
}
}
catch (InterruptedException ex) {
System.err.println(Thread.currentThread().getName() + " gets Interrupted");
}
}
}
Now if we run the program, it completes successfully.
4. Best Practices
- Since Java version 1.5, we have java.util.concurrent package which contains various new concurrency classes and frameworks that make our work easy while working in a multithreaded environment.
- For inter-thread communication, instead of using the old way of using
wait()
andnotify()
method, we can make use of BlockingQueue instead present in java.util.concurrent package. - BlockingQueue Interface represents a queue that is thread-safe to put into and take elements from while 2 Threads are communicating with each other, which in turn avoids any IllegalMonitorStateException as well.
- Lock Interface and ReentrantLock class provide more control over the concurrency as compared with synchronized block. Using it, a Thread can try for a lock without waiting, eliminating the chances of a deadlock situation.
- We can use other classes like CountDownLatch, CyclicBarrier, Exchanger, Phaser, SynchronousQueue in order to work with multiple threads in a multithreaded application.
5. Conclusion
In this article, we learned about IllegalMonitorStateException, what are the causes for this and how to prevent it in our code. We have also seen some of the best practices for using new concurrency classes that can help in avoiding the IllegalMonitorStateException.
Happy Learning !!
Sourcecode on Github
An IllegalMonitorStateException
is a runtime exception in Java that occurs in multithreaded applications. It indicates that the calling thread has attempted to wait on an object’s monitor, or attempted to notify other threads waiting on an object’s monitor, without owning the specified monitor.
Since the IllegalMonitorStateException
is an unchecked exception, it does not need to be declared in the throws
clause of a method or constructor.
What Causes IllegalMonitorStateException
When building multithreaded applications in Java, if a monitor needs to be synchronized on, the IllegalMonitorStateException
is thrown to indicate a thread attempted to wait or to notify other threads waiting on that monitor, without owning it.
Therefore, this exception occurs if one of the wait()
, notify()
or notifyAll()
methods of the Object
class are called outside a synchronized
block or method.
IllegalMonitorStateException Example
Here’s an example of an IllegalMonitorStateException
, thrown when the wait()
method is called outside a synchronized
block:
class MyRunnable implements Runnable {
public void run() {
try {
this.wait(100); // calling wait() without outside synchronized block
System.out.println("Thread in runnable state");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class IllegalMonitorStateExceptionExample {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread myThread = new Thread(myRunnable);
myThread.start();
}
}
Since a thread must own a lock on the object’s monitor before calling the wait()
method, calling it outside a synchronized
block throws an IllegalMonitorStateException.
Running the above code throws the exception:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Object.wait(Object.java:321)
at MyRunnable.run(IllegalMonitorStateExceptionExample.java:4)
at java.base/java.lang.Thread.run(Thread.java:832)
How to Resolve IllegalMonitorStateException
The IllegalMonitorStateException
can be resolved by calling the wait()
, notify()
and notifyAll()
methods after acquiring an object lock, i.e. within a synchronized
block or method.
The call to the wait()
method in the earlier example can be placed inside a synchronized
block to resolve the exception:
class MyRunnable implements Runnable {
public void run() {
synchronized (this) {
try {
this.wait(100);
System.out.println("Thread in runnable state");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class IllegalMonitorStateExceptionExample {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread myThread = new Thread(myRunnable);
myThread.start();
}
}
Calling the wait()
method within a synchronized
block helps acquire a lock on the object monitor, which fixes the issue. Running the above code produces the correct output as expected:
Thread in runnable state
Track, Analyze and Manage Errors With Rollbar
Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you to proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Java errors easier than ever. Sign Up Today!

The IllegalMonitorStateException
is related to multithreading programming. This tutorial describes and demonstrates the IllegalMonitorStateException
in Java.
the java.lang.IllegalMonitorStateException
in Java
The IllegalMonitorStateException
occurs when working with multithreading programming in Java. When we synchronize on a monitor, and a thread tries to wait or notify the other threads waiting on the monitor without owning it that time, the IllegalMonitorStateException
occurs.
If we call the methods wait()
, notify()
, or notifyAll()
from the object
class, which is not in the synchronized
block, this exception will be thrown. Let’s try an example in this scenario.
package delftstack;
class DemoClass implements Runnable {
public void run() {
try {
// The wait method is called outside the synchronized block
this.wait(100);
System.out.println("Thread can successfully run.");
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public class Example {
public static void main(String[] args) {
DemoClass DemoRunnable = new DemoClass();
Thread DemoThread = new Thread(DemoRunnable);
DemoThread.start();
}
}
The code above creates a class that implements the Runnable
class and then calls the wait
method outside the synchronized
block. The Example
creates a thread from the instance of DemoClass
.
It will throw the IllegalMonitorStateException
because the wait
method is called outside the synchronized
block, and the thread must own a lock on the monitor before we call the wait()
method. See output:
Exception in thread "Thread-0" java.lang.IllegalMonitorStateException: current thread is not owner
at java.base/java.lang.Object.wait(Native Method)
at delftstack.DemoClass.run(Example.java:7)
at java.base/java.lang.Thread.run(Thread.java:833)
To fix this exception, we must call the wait()
, notify()
, or notifyAll()
methods after the object
lock is acquired, which will be in the synchronized
block.
Now let’s put the wait()
method into the synchronized
block, then make the above code error-free. See example:
package delftstack;
class DemoClass implements Runnable {
public void run() {
synchronized (this) {
try {
// The wait method is called outside the synchronized block
this.wait(100);
System.out.println("Thread can successfully run.");
}
catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
}
public class Example {
public static void main(String[] args) {
DemoClass DemoRunnable = new DemoClass();
Thread DemoThread = new Thread(DemoRunnable);
DemoThread.start();
}
}
Now the wait()
method is inside the synchronized
block, and the lock on the object monitor is acquired, the code will run successfully. See output:
Thread can successfully run.
i posted this at the end of my last post, but that was a different problem so I assumed it was ok to start a new topic.
If i minimize the error message, the program still works, except that i can’t access the JMenu, and the error keeps writing in the window each time a key is pressed (wait() is for a keylistener). I have tried using synchronized(this) with wait(), and with both wait() and notify() or notifyAll(), no combination seems to work. When i used synchronized(this), the JFrame showing my arrow buttons appears blank. (it’s a game, and the arrow buttons are used (or arrow keys) to move around the game board)
EDIT:
I moved the try catch to the original class, and added a synchronized (new Levels ()) (name of class keylistener is in)
{
wait();
}
The arrows appeared and the keylistener worked, but the error message still appeared.
Here’s the error message, followed by a portion of my code, hopefully someone knows what to do. After waiting, the paint method in my original class is repainted.
java.lang.IllegalMonitorStateException: current thread not owner
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Unknown Source)
at Levels.LevelOne(Levels.java:582)
at User_Interface.paint(User_Interface.java:182)
at javax.swing.JFrame.update(Unknown Source)
at sun.awt.RepaintArea.paint(Unknown Source)
at sun.awt.windows.WComponentPeer.handleEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
//***Levels class in which the wait() command is executed, waiting for a key
//to be pressed
up = new JButton (new ImageIcon ("arrow_up.gif"));
left = new JButton (new ImageIcon ("arrow_left.gif"));
right = new JButton (new ImageIcon ("arrow_right.gif"));
down = new JButton (new ImageIcon ("arrow_down.gif"));
f.getContentPane ().setLayout (new BorderLayout ());
f.getContentPane ().add (up, BorderLayout.NORTH);
f.getContentPane ().add (left, BorderLayout.WEST);
f.getContentPane ().add (right, BorderLayout.EAST);
f.getContentPane ().add (down, BorderLayout.SOUTH);
f.pack ();
f.setLocation (600, 350);
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
f.setVisible (true);
KeyHandler key = new KeyHandler ();
up.addKeyListener (key);
left.addKeyListener (key);
right.addKeyListener (key);
down.addKeyListener (key);
up.addActionListener (new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
yCord -= 1;
yLoc += 40;
label = "LevelOne";
ok = true;
f.setVisible (false);
}
}
);
left.addActionListener (new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
xCord -= 1;
xLoc += 40;
label = "LevelOne";
ok = true;
f.setVisible (false);
}
}
);
right.addActionListener (new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
xCord += 1;
xLoc -= 40;
ok = true;
label = "LevelOne";
f.setVisible (false);
}
}
);
down.addActionListener (new ActionListener ()
{
public void actionPerformed (ActionEvent e)
{
yCord += 1;
yLoc -= 40;
label = "LevelOne";
ok = true;
f.setVisible (false);
}
}
);
while (!ok)
{
try
{
wait ();
}
catch (InterruptedException e)
{
}
}
ok = false;
}
Message was edited by:
jacob2932
posted 20 years ago
-
-
Number of slices to send:
Optional ‘thank-you’ note:
-
-
Steve,
Using 1.4 is not mandated for the SCJD: however, I can’t really see any reason not to use it: with regex support, exception chaining, interuptable File IO, Channels, etc., there are a lot of good tools available there that were not available before.
My opinion is that it will make passing the test easier, because it offers you more abilities.
This is sort of the point of my book, in addition to exploring the details of how(and why) RMI, Swing, and Threading work. I didn’t just want to write a book to write a book: My goal was to provide a useful resource.
As for your locking issue:
Since I’m using RMI the locking strategy is based on the fact that only the thread that locked the record can unlock it.
My advice is to be somewhat careful here. Read the documentation for your unlock method very carefully. From what you’re saying, I’m not sure that you’re adhearing to the letter of the unlock method, as it was presented to me.
This would be fine if the RMIRegistry does not use a thread pool to service requests. Obviously, a thread pool would mean that a different client could be assigned the same thread and could therefore unlock a record that it didn’t lock. The worst case would be if the Registry server was not multithreaded and only used ONE thread for all clients (I know this is unlikely but it is an implementation detail), since this would mean that every client could unlock any record they choose.
Well, there are lot of potential directions to explore here. I don’t want to give away too much(and I wouldn’t want to deter you from buying my book ), but there are other solutions, even using RMI. For example, you know that each RMI object get’s at least one thread per client: so what if each GUI client got thier own RMI object, and all of those RMI object coordinated though a single threadsafe object? Maybe a factory(say, an RMI object itself) could create these RMI objects for you? Does this sound like the way ejbs work with the Home interface? Just some food for thought…
There is also the side issue of a reference to the thread remaining in the HashMap until a client unlocks the record. This could result in a memory leak as a dead thread could not be garbage collected.
Try exploring the object
here
HTH,
M
[ July 15, 2002: Message edited by: Max Habibi ]
The most important thing in multi-threading is serializing the simultaneous access to the objects, otherwise these multiple threads will leave this object in an unstable state.For this purpose locks have been introduced.
The synchronized keyword is the easiest one for providing synchronization between the threads and it has an intrinsic lock associated with it.When a method is declared to be synchronized then only one thread can gain access to the method at a time.The next thread will get a chance only after the previous thread exits the method.
When a thread gains access but has no sufficient sources to accomplish its tasks then it has to give chance to other threads.For this purpose wait(),notify(),notifyAll() methods have been introduced.
Note: In Thread class there is no methods like wait() or notify() is available.It is only available in Object class.So any objects can call this method.Calling this method outside the synchronized block will also throw this exception.
In java API documentation it is given that calling these methods will throw java.lang. IllegalMonitorStateException when the current thread is not the owner of the object’s lock.
Let us see in detail,when this illegalMonitorStateException is thrown.
There are two possible ways,a synchronized keyword can be used to acquire the lock.
1.A method can be declared as synchronized.
2.Using a synchronized block to acquire a lock on an specific object.
When a method is declared as synchronized,then all the threads are synchronized by the class object that contains this method i.e,All the threads can have locks over the class object.
I have explained this concept with a bank containing three accounts.we have to trasfer funds from one account to other accounts.This transfering process is carried out by each threads.
The following two programs are written by cay s.Horstmann in (Core Java,VolumeI),
Copyright© 2008 Sun Microsystems,Inc. I have modified this program so as to make it simple to explain this exception.
Program:
public class UnsynchBank
{
public static void main(String[] args)throws InterruptedException
{
Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
int i;
TransferRunnable r = new TransferRunnable(b, 0,1,500,INITIAL_BALANCE);
t = new Thread(r);
t.start();
TransferRunnable r2 = new TransferRunnable(b, 0,2,500,INITIAL_BALANCE);
t1=new Thread(r2);
t1.start();
}
private static Thread t,t1;
public static final int NACCOUNTS = 3;
public static final double INITIAL_BALANCE = 1000;
}
class Bank
{
public Bank(int n, double initialBalance)throws InterruptedException
{
accounts = new double[n];
for (int i = 0; i < accounts.length; i++)
accounts[i] = initialBalance;
}
public synchronized void transfer(int from, int to, double amount) throws InterruptedException
{
while(accounts[from]
{
System.out.println(«i am entering into wait set:»+Thread.currentThread());
wait();//This wait() method is called by the thread that has acquired lock on the class object Bank
}
accounts[from] -= amount;
accounts[to] += amount;
System.out.println(«I am the current thread:»+Thread.currentThread());
System.out.println(«source:»+from);
System.out.println(«to:»+to);
System.out.println(«amount:»+amount);
System.out.printf(«Total Balance: %10.2f%n», getTotalBalance());
System.out.println(«currentthread»+Thread.currentThread());
notify();//This notify() method is called by the thread that has acquired a lock on the class object Bank
System.out.println();
}
public synchronized double getTotalBalance()
{
double sum = 0;
for (double a : accounts)
sum += a;
return sum;
}
private final double[] accounts;
}
class TransferRunnable implements Runnable
{
public TransferRunnable(Bank b, int from,int to,int a, double max)
{
bank = b;
fromAccount = from;
toaccount=to;
amt=a;
maxAmount = max;
}
public void run()
{
try
{
int toAccount = toaccount;
int amount = amt;
bank.transfer(fromAccount, toAccount, amount);
Thread.sleep((int) (DELAY * Math.random()));
}
catch (InterruptedException e)
{
}
}
private Bank bank;
private int fromAccount;
private double maxAmount;
private int toaccount;
private int amt;
private int DELAY = 10;
}
Output:
I am the current thread:Thread[Thread-1,5,main]
source:0
to:2
amount:500.0
Total Balance: 3000.00
currentthreadThread[Thread-1,5,main]
I am the current thread:Thread[Thread-0,5,main]
source:0
to:1
amount:500.0
Total Balance: 3000.00
currentthreadThread[Thread-0,5,main]
In the above program all the threads are synchronized by the Bank class object.I have shown this by highlighting those statements in the program. If you try to call wait() or notify() on any other objects IllegalMonitorStateException will be thrown. For eg, if you try to call accounts.wait(); this will throw illegalmonitorstateexception because all threads have acquired the lock on the class object Bank not on the accounts object.
Using synchronized blocks:
Program:
In the above program change the transfer method as follows to use synchronized blocks to acquire locks.
public void transfer(int from, int to, double amount) throws InterruptedException
{
synchronized(accounts) //All the threads are synchronized on the accounts object
{
while(accounts[from]
{
System.out.println(«i am entering into wait set:»+Thread.currentThread());
accounts.wait();//wait() method is called by the thread that has a lock on the accounts object
}
accounts[from] -= amount;
accounts[to] += amount;
System.out.println(«I am the current thread:»+Thread.currentThread());
System.out.println(«source:»+from);
System.out.println(«to:»+to);
System.out.println(«amount:»+amount);
System.out.printf(«Total Balance: %10.2f%n», getTotalBalance());
System.out.println(«currentthread»+Thread.currentThread());
accounts.notify();//notify() method is called by the thread that has a lock on the accounts object.
System.out.println();
}
}
output:
I am the current thread:Thread[Thread-0,5,main]
source:0
to:1
amount:500.0
Total Balance: 3000.00
currentthreadThread[Thread-0,5,main]
Bank@1b67f74
Exception in thread «Thread-0» I am the current thread:Thread[Thread-1,5,main]ja
va.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
source:0 at Bank.transfer(UnsynchBank.java:70)
at TransferRunnable.run(UnsynchBank.java:129)
to:2 at java.lang.Thread.run(Unknown Source)
amount:500.0
Total Balance: 3000.00
currentthreadThread[Thread-1,5,main]
Bank@1b67f74
Exception in thread «Thread-1» java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at Bank.transfer(UnsynchBank.java:70)
at TransferRunnable.run(UnsynchBank.java:129)
at java.lang.Thread.run(Unknown Source)
If you see the program,all the threads are synchronized on the accounts object.So when calling the wait() or notify() method all the thread should specify the object on which it has acquired the lock,for eg, accounts.wait(). Simply calling the wait() method indicates that we are trying to call wait() on the bank object not on the accounts object.
So when we synchronize the threads using a paricular object obj.We should call obj.wait() or obj.notify().
The code calling the lock is located within a JSP
Lock lock = Hazelcast.getLock(«some.jsp»);
try {
lock.lock();
// ..
// do some rather specific logics, that is important to be handled only one at a time
// also including database access
} finally {
lock.unlock();
}
Try placing the lock.lock outside of the try/catch:
Lock lock = Hazelcast.getLock(«some.jsp»);
lock.lock();
try { // ..
// do some rather specific logics, that is important to be
handled only one at a time
// also including database access
} finally {
lock.unlock();
}
In that case the will never be an unlock, of the lock could not be acquired.
On Fri, Sep 7, 2012 at 2:11 PM, Jacum ICT notifications@github.com wrote:
The code calling the lock is located within a JSP
Lock lock = Hazelcast.getLock(«some.jsp»);
try {
lock.lock();// .. // do some rather specific logics, that is important to be handled only one at a time // also including database access
} finally {
lock.unlock();
}—
Reply to this email directly or view it on GitHubhttps://github.com//issues/267#issuecomment-8362384.
Interesting idea.
Why would it change anything?
Are there any references that JDK 1.7 is known for running code in finally { } blocks in other thread than the main try { } body?
On Fri, Sep 7, 2012 at 3:09 PM, Jacum ICT notifications@github.com wrote:
Interesting idea.
Why would it change anything?
The error you get is that you are releasing a lock that is not owned. If
you do the lock within the try/finally, and the lock.lock fails.. the lock
will be unlocked resulting in the error you get.
So try what I suggested.
Are there any references that JDK 1.7 is known for running code in finally
{ } blocks in other thread than the main try { } body?
From: Peter Veentjer [notifications@github.com]
Sent: Friday, September 07, 2012 14:07
To: hazelcast/hazelcast
Cc: Timur Evdokimov
Subject: Re: [hazelcast] JDK 1.7: java.lang.IllegalMonitorStateException:
Current thread is not owner of the lock! (#267)Try placing the lock.lock outside of the try/catch:
Lock lock = Hazelcast.getLock(«some.jsp»);
lock.lock();
try { // ..
// do some rather specific logics, that is important to be
handled only one at a time
// also including database access} finally {
lock.unlock();
}In that case the will never be an unlock, of the lock could not be
acquired.On Fri, Sep 7, 2012 at 2:11 PM, Jacum ICT notifications@github.com
wrote:The code calling the lock is located within a JSP
Lock lock = Hazelcast.getLock(«some.jsp»);
try {
lock.lock();// ..
// do some rather specific logics, that is important to be handled only
one at a time
// also including database access} finally {
lock.unlock();
}—
Reply to this email directly or view it on GitHub<
https://github.com/hazelcast/hazelcast/issues/267#issuecomment-8362384>.—
Reply to this email directly or view it on GitHub<
https://github.com/hazelcast/hazelcast/issues/267#issuecomment-8363380>.—
Reply to this email directly or view it on GitHubhttps://github.com//issues/267#issuecomment-8363429.
What would be interesting to know is why the lock.lock fails. Currently
that exception is ‘lost’ due to the exception thrown in the finally clause.
On Fri, Sep 7, 2012 at 3:12 PM, Peter Veentjer alarmnummer@gmail.comwrote:
On Fri, Sep 7, 2012 at 3:09 PM, Jacum ICT notifications@github.comwrote:
Interesting idea.
Why would it change anything?
The error you get is that you are releasing a lock that is not owned. If
you do the lock within the try/finally, and the lock.lock fails.. the lock
will be unlocked resulting in the error you get.So try what I suggested.
Are there any references that JDK 1.7 is known for running code in
finally { } blocks in other thread than the main try { } body?
From: Peter Veentjer [notifications@github.com]
Sent: Friday, September 07, 2012 14:07
To: hazelcast/hazelcast
Cc: Timur Evdokimov
Subject: Re: [hazelcast] JDK 1.7: java.lang.IllegalMonitorStateException:
Current thread is not owner of the lock! (#267)Try placing the lock.lock outside of the try/catch:
Lock lock = Hazelcast.getLock(«some.jsp»);
lock.lock();
try { // ..
// do some rather specific logics, that is important to be
handled only one at a time
// also including database access} finally {
lock.unlock();
}In that case the will never be an unlock, of the lock could not be
acquired.On Fri, Sep 7, 2012 at 2:11 PM, Jacum ICT notifications@github.com
wrote:The code calling the lock is located within a JSP
Lock lock = Hazelcast.getLock(«some.jsp»);
try {
lock.lock();// ..
// do some rather specific logics, that is important to be handled only
one at a time
// also including database access} finally {
lock.unlock();
}—
Reply to this email directly or view it on GitHub<
https://github.com/hazelcast/hazelcast/issues/267#issuecomment-8362384>.—
Reply to this email directly or view it on GitHub<
https://github.com/hazelcast/hazelcast/issues/267#issuecomment-8363380>.—
Reply to this email directly or view it on GitHubhttps://github.com//issues/267#issuecomment-8363429.
Thanks for you suggestion, will try that.
Still, doing static code analysis, I’m puzzled: if lock.lock() fails, it must leave some traces.
This is just try { } finally { } construction, if an exception is thrown, it must show up as a stacktrace elsewhere — and it does not. So if lock.lock() does not acquire the said lock, it happens somehow quietly.
On Fri, Sep 7, 2012 at 3:18 PM, Jacum ICT notifications@github.com wrote:
Thanks for you suggestion, will try that.
Still, doing static code analysis, I’m puzzled: if lock.lock() fails, it
must leave some traces.
Normally it does. But the exception now is lost due to an exception in the
finally clause.
If you move the lock.lock outside the try/finally, I’m pretty sure you will
see that lock.lock has thrown an exception.
This is just try { } finally { } construction, if an exception is thrown,
it must show up as a stacktrace elsewhere — and it does not. So if
lock.lock() does not acquire the said lock, it happens somehow quietly.—
Reply to this email directly or view it on GitHubhttps://github.com//issues/267#issuecomment-8363601.
For more information about this ‘lost exception’ problem, have a peek at
this:
http://accu.org/index.php/journals/236
On Fri, Sep 7, 2012 at 3:22 PM, Peter Veentjer alarmnummer@gmail.comwrote:
On Fri, Sep 7, 2012 at 3:18 PM, Jacum ICT notifications@github.comwrote:
Thanks for you suggestion, will try that.
Still, doing static code analysis, I’m puzzled: if lock.lock() fails, it
must leave some traces.Normally it does. But the exception now is lost due to an exception in the
finally clause.If you move the lock.lock outside the try/finally, I’m pretty sure you
will see that lock.lock has thrown an exception.This is just try { } finally { } construction, if an exception is
thrown, it must show up as a stacktrace elsewhere — and it does not. So if
lock.lock() does not acquire the said lock, it happens somehow quietly.—
Reply to this email directly or view it on GitHubhttps://github.com//issues/267#issuecomment-8363601.
Thank you Peter, I learned something new again.
Unfortunately, moving lock.lock() out of the try {} block didn’t help.
We were running test with Hazelcast 2.3, there are far less occurences of the issue, however not zero.
There are still cases like this:
java.lang.IllegalMonitorStateException: Current thread is not owner of the lock!
at com.hazelcast.impl.MProxyImpl$MProxyReal.unlock(MProxyImpl.java:731)
at sun.reflect.GeneratedMethodAccessor464.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.hazelcast.impl.MProxyImpl$DynamicInvoker.invoke(MProxyImpl.java:66)
at $Proxy514.unlock(Unknown Source)
while no exception is seen thrown by lock.lock() — obviously, otherwise unlock() won’t be reached.
This is a highly concurrent test with ~2000 simulated clients and for ~300000 invocations of the same code only 4 occurences if this issue, so this must be quite elusive race condition.
For the whole test, absolutely no exceptions were seen thrown by lock.lock().
Is there any logging on current state of the distributed locks in Hazelcast that we could switch on?
E.g. which thread is holding that failed lock, exactly?
Can you post the code of invocations? Let us see if we can reproduce on our side.
The invocation code is like it was written above:
Lock lock = Hazelcast.getLock(«some.jsp»);
lock.lock();
try {
// ..
// do some rather specific logics, that is important to be handled only one at a time
// also including database access
} finally {
lock.unlock(); // here it throws an exception
}
We have noticed that issue only recently, when we were doing tests with JDK 1.7
We will try once again with JDK 1.6 and Hazelcast 2.3, and let you know if there are any occurences.
Also: it seems like Hazelcast 2.3 has much less of these errors than 2.2.
Though this is not very exact science: so far we did just one run with each.
More observations I could add:
- this is massively parallel test, sometimes with up to 20+ threads competing for the same lock — (observed in cases the IllegalMonitorStateException has been thrown)
- the test is running on just one node and just one Hazelcast instance, so issues with inter-node communication, network glitches etc. are not applicable heere.
Thanks for the info.
I am able to reproduce this issue. As you said, this is a quite elusive
race condition. (Increasing execution frequency of cleanup thread helps to
much here.) Problem appears both on jdk6 and jd7.
I have also a fix and will push after some testing.
@mmdogan
Yes, this matches our today’s observations: we also reproduced the same issue on JDK6.
Thank you for quick reaction.
Hi Mehmet, have you got any updates on this?
Any workarounds?
I will push the fix soon to master branch (currently working on a related
issue).
Then you will be able to test. If you confirm the fix, it will be part of
v2.3.2.
@mmdogan
~ Sent from mobile
On Sep 16, 2012 2:34 PM, «Jacum ICT» notifications@github.com wrote:
Hi Mehmet, have you got any updates on this?
Any workarounds?—
Reply to this email directly or view it on GitHubhttps://github.com//issues/267#issuecomment-8594127.
Mehmet,
Few questions, if I may ask.
Have you got an estimate when 2.3.2 is going to be released ‘officially’?
Is it worth trying the current code from master in a load test?
Kind regards,
Timur
We are planning to release 2.3.2 in a month. Yes, code in master branch is
fairly stable, you should be able to test.
@mmdogan
Mehmet, we have repeated the test with Hazelcast bulld made from 2.3.2 master (about a week ago), and there are still occurrences of this:
java.lang.IllegalMonitorStateException: Current thread is not owner of the lock!
at com.hazelcast.impl.MProxyImpl$MProxyReal.unlock(MProxyImpl.java:731)
at sun.reflect.GeneratedMethodAccessor621.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.hazelcast.impl.MProxyImpl$DynamicInvoker.invoke(MProxyImpl.java:66)
at $Proxy526.unlock(Unknown Source)
at com.hazelcast.impl.MProxyImpl.unlock(MProxyImpl.java:412)
at com.hazelcast.impl.LockProxyImpl$LockProxyBase.unlock(LockProxyImpl.java:202)
at com.hazelcast.impl.LockProxyImpl.unlock(LockProxyImpl.java:116)
The code using Lock API didn’t change since last try, and the stats are much better this time (used to be 4/300000, now the test has been running for about 100 hours and we got just 2 occurrences on ~2,6 million requests) but the problem is still not solved completely.
I just reproduced this again with 2.4.1
The code is pretty simple as described above:
jobLock.lock();
try {
// add to a distributed IMap
} finally {
jobLock.unlock();
}
java.lang.IllegalMonitorStateException: Current thread is not owner of the lock!
at com.hazelcast.impl.MProxyImpl$MProxyReal.unlock(MProxyImpl.java:731)
at sun.reflect.GeneratedMethodAccessor23.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at com.hazelcast.impl.MProxyImpl$DynamicInvoker.invoke(MProxyImpl.java:66)
at $Proxy0.unlock(Unknown Source)
at com.hazelcast.impl.MProxyImpl.unlock(MProxyImpl.java:412)
at com.hazelcast.impl.LockProxyImpl$LockProxyBase.unlock(LockProxyImpl.java:202)
at com.hazelcast.impl.LockProxyImpl.unlock(LockProxyImpl.java:116)
This was on open JDK 1.6…Let me know if I can provide any more details
the same Problem
code like this
public void run() {
for (;;) {
try {
RedisBean bean = redisQueue.take();
final String url = bean.getCQ_SOURCE_URL();
final String key = MD5.getMD5(url);
MyHazelcast.defaultMap.tryLock(key);
if(!MyHazelcast.defaultMap.containsKey(key)){
MyHazelcast.defaultMap.put(key, 0);
...................
// 存储日志
ApperLog.recordLog(bean);
}
MyHazelcast.defaultMap.unlock(key);
//System.out.println(bean.getCQ_SOURCE_URL());
}catch (Exception e) {
log.error(e.getMessage(),e);
}
}
}
basic in jdk 1.7 ,and the hazelcast version is 2.5
java.lang.RuntimeException: Current thread is not owner of the lock!
at com.hazelcast.impl.ClientServiceException.readData(ClientServiceException.java:63)
at com.hazelcast.nio.Serializer$DataSerializer.read(Serializer.java:104)
at com.hazelcast.nio.Serializer$DataSerializer.read(Serializer.java:79)
at com.hazelcast.nio.AbstractSerializer.toObject(AbstractSerializer.java:121)
at com.hazelcast.nio.AbstractSerializer.toObject(AbstractSerializer.java:156)
at com.hazelcast.client.ClientThreadContext.toObject(ClientThreadContext.java:72)
at com.hazelcast.client.IOUtil.toObject(IOUtil.java:34)
at com.hazelcast.client.ProxyHelper.getValue(ProxyHelper.java:186)
at com.hazelcast.client.ProxyHelper.doOp(ProxyHelper.java:146)
at com.hazelcast.client.ProxyHelper.doOp(ProxyHelper.java:140)
at com.hazelcast.client.MapClientProxy.unlock(MapClientProxy.java:193)
at com.loongtao.secrawler.MyRunnable$SaveOf.run(MyRunnable.java:60)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
I agree with fridgebuzz, this issue is not fixed as of version 2.5 and should be reopened
Does this issue mean that locks are broken and should not be used?
Thanks,
yoram
ykulbak, No, it does not mean that at all. Locking is absolutely necessary to accomplish some things. This exception that gets thrown is invalid, but locking from a cluster perspective still works correctly as far as I can tell. I tried to see if I could find the issue in code, but the problem is definitely not obvious.
So what I did is I built a wrapper around the hazelcast lock that addresses this issue. The wrapper tracks locking from a local perspective, and if this exception is thrown at a point where the local locking looks correct, the wrapper just swallows the exception. It’s a complete hack to work around this problem, but it does work, and it does prevent my other code from having to deal with these exceptions when they are thrown incorrectly.
As I really depend on distributed locks here is a very simple way to reproduce the issue.
My specs:
Debian Wheezy 2.6.32-5-amd64
JDK 1.6.0_32
Hazelcast 2.5
The steps to reproduce:
1)Run two instances of server.sh to form a cluster.
2)Run this simple code and press enter a few times if you like but should block before unlock method.
3)Hit Ctrl+C on one of the nodes consoles.
4)Hit enter and there you go:java.lang.RuntimeException: Current thread is not owner of the lock!
WARNING: [192.168.100.90]:5702 [dev] exception during handling LOCK_UNLOCK: Current thread is not owner of the lock!
java.lang.IllegalMonitorStateException: Current thread is not owner of the lock!
at com.hazelcast.impl.MProxyImpl$MProxyReal.unlock(MProxyImpl.java:731)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
The code to reproduce it:
public static void main(String[] args) {
ClientConfig clientConfig = new ClientConfig();
clientConfig.addAddress(«Your IP here:5701»);
HazelcastInstance client = HazelcastClient.newHazelcastClient(clientConfig);
final ILock lock = client.getLock("lock");
Scanner s = new Scanner(System.in);
while (true) {
lock.lock();
try {
System.out.println("Locked now:");
s.nextLine();
} catch (Exception e) {
} finally {
try {
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
hi,
Maybe a workaround on that is the following:
boolean locked = false;
try{
locked = lock.trylock();
if(locked){
// do something
}
} finally {
if(locked){
lock.unlock
}
}
I’m having the same issue with a 1 producer, n consumers setup… it triggers pretty fast. I am not using the client. Hazelcast 3.2. I am specifically using a Condition on the lock.
Consumer is basically:
lock.lock();
try {
// maybe do work here
condition.await(timeout, unit);
// maybe do work here
} finally {
lock.unlock();
}
This is a big bummer… this is only my first day using Hazelcast!
Exception in thread «Consumer-0» java.lang.IllegalMonitorStateException: Current thread is not owner of the lock! -> Owner: null, thread-id: 0
at com.hazelcast.concurrent.lock.operations.UnlockOperation.ensureUnlocked(UnlockOperation.java:70)
at com.hazelcast.concurrent.lock.operations.UnlockOperation.unlock(UnlockOperation.java:64)
at com.hazelcast.concurrent.lock.operations.UnlockOperation.run(UnlockOperation.java:56)
at com.hazelcast.spi.impl.BasicOperationService.processOperation(BasicOperationService.java:363)
at com.hazelcast.spi.impl.BasicOperationService.processPacket(BasicOperationService.java:309)
at com.hazelcast.spi.impl.BasicOperationService.access$400(BasicOperationService.java:102)
at com.hazelcast.spi.impl.BasicOperationService$BasicOperationProcessorImpl.process(BasicOperationService.java:756)
at com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.process(BasicOperationScheduler.java:276)
at com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.doRun(BasicOperationScheduler.java:270)
at com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.run(BasicOperationScheduler.java:245)
at —— End remote and begin local stack-trace ——.(Unknown Source)
at com.hazelcast.spi.impl.BasicInvocation$InvocationFuture.resolveResponse(BasicInvocation.java:836)
at com.hazelcast.spi.impl.BasicInvocation$InvocationFuture.resolveResponseOrThrowException(BasicInvocation.java:769)
at com.hazelcast.spi.impl.BasicInvocation$InvocationFuture.get(BasicInvocation.java:696)
at com.hazelcast.spi.impl.BasicInvocation$InvocationFuture.get(BasicInvocation.java:674)
at com.hazelcast.spi.impl.BasicInvocation$InvocationFuture.getSafely(BasicInvocation.java:687)
at com.hazelcast.concurrent.lock.LockProxySupport.unlock(LockProxySupport.java:113)
at com.hazelcast.concurrent.lock.LockProxy.unlock(LockProxy.java:97)
Also, this:
Apr 10, 2014 1:49:05 PM com.hazelcast.concurrent.lock.operations.AwaitOperation
SEVERE: [10.200.2.113]:5701 [dev] [3.2] null
java.lang.IllegalStateException
at com.hazelcast.concurrent.lock.ConditionInfo.startWaiter(ConditionInfo.java:61)
at com.hazelcast.concurrent.lock.LockResourceImpl.startAwaiting(LockResourceImpl.java:180)
at com.hazelcast.concurrent.lock.LockStoreImpl.startAwaiting(LockStoreImpl.java:233)
at com.hazelcast.concurrent.lock.operations.AwaitOperation.beforeRun(AwaitOperation.java:50)
at com.hazelcast.spi.impl.BasicOperationService.processOperation(BasicOperationService.java:355)
at com.hazelcast.spi.impl.BasicOperationService.runOperation(BasicOperationService.java:228)
at com.hazelcast.concurrent.lock.operations.UnlockOperation.afterRun(UnlockOperation.java:85)
at com.hazelcast.spi.impl.BasicOperationService.processOperation(BasicOperationService.java:389)
at com.hazelcast.spi.impl.BasicOperationService.access$300(BasicOperationService.java:102)
at com.hazelcast.spi.impl.BasicOperationService$BasicOperationProcessorImpl.process(BasicOperationService.java:754)
at com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.process(BasicOperationScheduler.java:276)
at com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.doRun(BasicOperationScheduler.java:270)
at com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.run(BasicOperationScheduler.java:245)
Can you create a test that reproduces the problem.
This saves us a lot of time.
On Thu, Apr 10, 2014 at 9:50 PM, Devin Smith notifications@github.comwrote:
Also, this:
Apr 10, 2014 1:49:05 PM
com.hazelcast.concurrent.lock.operations.AwaitOperation
SEVERE: [10.200.2.113]:5701 [dev] [3.2] null
java.lang.IllegalStateException
at
com.hazelcast.concurrent.lock.ConditionInfo.startWaiter(ConditionInfo.java:61)
at
com.hazelcast.concurrent.lock.LockResourceImpl.startAwaiting(LockResourceImpl.java:180)
at
com.hazelcast.concurrent.lock.LockStoreImpl.startAwaiting(LockStoreImpl.java:233)
at
com.hazelcast.concurrent.lock.operations.AwaitOperation.beforeRun(AwaitOperation.java:50)
at
com.hazelcast.spi.impl.BasicOperationService.processOperation(BasicOperationService.java:355)
at
com.hazelcast.spi.impl.BasicOperationService.runOperation(BasicOperationService.java:228)
at
com.hazelcast.concurrent.lock.operations.UnlockOperation.afterRun(UnlockOperation.java:85)
at
com.hazelcast.spi.impl.BasicOperationService.processOperation(BasicOperationService.java:389)
at
com.hazelcast.spi.impl.BasicOperationService.access$300(BasicOperationService.java:102)
at
com.hazelcast.spi.impl.BasicOperationService$BasicOperationProcessorImpl.process(BasicOperationService.java:754)at
com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.process(BasicOperationScheduler.java:276)
at
com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.doRun(BasicOperationScheduler.java:270)
at
com.hazelcast.spi.impl.BasicOperationScheduler$PartitionThread.run(BasicOperationScheduler.java:245)Reply to this email directly or view it on GitHubhttps://github.com//issues/267#issuecomment-40123566
.
Ok, I’ve got a simple example that reproduces the problem:
https://github.com/devinrsmith/hazelcast_test
I know it’s might be a little stupid to wrap up a hazelcast queue in a hazelcast lock, but it turns out it also exhibits the problem without the hazelcast queue (if you keep everything in process and pass in a singleton linked list).
It might take a few restarts. Only 1 process necessary.
@pveentjer , have you been able to reproduce the issue?
For note: the SpamLockCondition test seems to be stable with 2 threads, but crashes with 3 or more threads.
@pveentjer As far as I understood him on Skype he found the problem for the condition problem and prepares a PR for it. Maybe (hopefully) it is connected to your problem
We’re having a related issue in a cluster failover test with HZ-2.6.8.
We’re running a HZ cluster of 2 nodes.
Looks like if a key is locked from one of the two nodes and the same node is shut down before the unlock, the key remains locked forever.
It’s like as the ownership of the lock doesn’t get migrated.
Locks are redesigned from scratch.
Closing the issue. please try with latest (at least 3.2)
Please reopen the problem
I would be nice to have the fix backported to 2.x
Patrizio Munzi
email: patrizio.munzi@gmail.com
mobile: +39 393 7195164
skype: patrizio.munzi
On 28 May 2014, at 16:00, toktarev notifications@github.com wrote:
Please reopen the problem
—
Reply to this email directly or view it on GitHub.
AwaitOperation
is not related to this problem. We already know condition api has some bugs and there’s an ongoing work to fix them. Also 2.x branch doesn’t support conditions and this issue is reported for 2.x version.
For condition defects, please file a new issue.
Are you able to reproduce directly this issue without conditions? Can you send a test case?
Your split brain lock issue is also not related to the original issue. Currently Hazelcast doesn’t support lock merging. So, after merge happens, locks owner node changes and other lock’s unlock request fails with IllegalMonitorStateException
.
You can create a separate issue for lock split brain. Here is current condition issue: #2272
We cannot backport current lock fixes to the 2.x branch, since lock codebase is completely different.
Are you able to reproduce directly this issue without conditions? Can you send a test case?
It is reproduced directly with conditions on last 3.2 version