Java.lang.IllegalMonitorStateException trhown when calling signal ()
i runs in a multithreaded program. The threads are running in a matrix (workerThread), and I have a thread (display) that prints the matrix state. Getting this exception, inside the scaleRow () class of the Matrix class on the monitor.signal () line
can someone tell me what is wrong?
public class Matrix {
private int row;
private int column;
private int[][] matrix;
private Map<Integer, String> mapForRow;
private Map<Integer, String> mapForColumn;
private Lock lock;
private Condition condition;
private Condition monitor;
private boolean rowIncreased;
private boolean columnIncreased;
private boolean columnCanBeAdded;
private boolean rowCanBeAdded;
private boolean print;
public Matrix(int row, int column) {
this.matrix = new int[row][column];
lock = new ReentrantLock();
mapForColumn = new LinkedHashMap<Integer, String>();
mapForRow = new LinkedHashMap<Integer, String>();
condition = lock.newCondition();
monitor = lock.newCondition();
rowIncreased = false;
columnIncreased = false;
rowCanBeAdded = false;
columnCanBeAdded = false;
print = false;
}
public void increaseRow(int row) {
if (!mapForRow.containsKey(row))
mapForRow.put(row, "not increased");
if (mapForRow.get(row).equals("not increased") && !columnIncreased) {
mapForRow.get(row).equals("increased");
rowIncreased = true;
for (int j = 0; j < matrix.length; j++)
setMatrix(row, j, matrix[row][j] + 1);
mapForRow.put(row, "not increased");
rowIncreased = false;
print = true;
monitor.signal();
}
}
public void increaseColumn(int column) {
if (!mapForColumn.containsKey(column))
mapForColumn.put(column, "not increased");
if (mapForColumn.get(column).equals("not increased") && !rowIncreased) {
mapForColumn.get(column).equals("increased");
columnIncreased = true;
for (int i = 0; i < matrix.length; i++)
setMatrix(i, column, matrix[i][column] + 1);
mapForColumn.put(column, "not increased");
columnIncreased = false;
print = true;
monitor.signal();
}
}
public int sumColumn(int column) {
lock.lock();
int sum = 0;
try {
columnCanBeAdded = false;
while (columnIncreased || rowIncreased || rowCanBeAdded) {
condition.await();
}
for (int i = 0; i < matrix.length; i++)
sum += matrix[i][column];
columnCanBeAdded = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
condition.signalAll();
print = true;
monitor.signal();
return sum;
}
public int sumRow(int row) {
lock.lock();
int sum = 0;
try {
rowCanBeAdded = false;
while (columnIncreased || rowIncreased || columnCanBeAdded) {
condition.await();
}
for (int j = 0; j < matrix.length; j++)
sum += matrix[row][j];
rowCanBeAdded = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
condition.signalAll();
print = true;
monitor.signal();
return sum;
}
public void printMatrix() {
lock.lock();
try {
while (!print) {
monitor.await();
}
System.out.println("begin print matrix");
for (int i = 0; i < row; i++) {
System.out.println();
for (int j = 0; j < column; j++)
System.out.print(matrix[i][j]);
}
System.out.println("end print matrix");
print = false;
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void setMatrix(int row, int column, int number) {
matrix[row][column] = number;
}
public static void main(String[] args) {
Matrix matrix = new Matrix(10, 10);
for (int i = 0; i < 10; i++)
for (int j = 0; j < 10; j++)
matrix.setMatrix(i, j, 0);
for (int i = 0; i < 10; i++) {
WorkerThread workerThread = new WorkerThread(matrix);
workerThread.start();
}
// print the matrix state
Display display = new Display(matrix);
display.start();
}
}
display class:
public class Display extends Thread {
private Matrix matrix;
public Display(Matrix matrix) {
this.matrix = matrix;
}
@Override
public void run() {
while(true)
matrix.printMatrix();
}
}
workerThread class:
public class WorkerThread extends Thread {
private Matrix matrix;
public WorkerThread(Matrix matrix) {
this.matrix = matrix;
}
@Override
public void run() {
// prevent thread to die
while (true) {
matrix.increaseColumn(new Random().nextInt(9));
matrix.increaseRow(new Random().nextInt(9));
try {
sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
matrix.sumRow(new Random().nextInt(9));
matrix.sumColumn(new Random().nextInt(9));
}
}
}
UPDATE
Exception in thread "Thread-7" Exception in thread "Thread-6" Exception in thread "Thread-4" Exception in thread "Thread-1" Exception in thread "Thread-5" Exception in thread "Thread-9" Exception in thread "Thread-0" Exception in thread "Thread-2" Exception in thread "Thread-3" Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1941)
at Matrix.increaseColumn(Matrix.java:67)
at WorkerThread.run(WorkerThread.java:15)
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.signal(AbstractQueuedSynchronizer.java:1941)
at Matrix.increaseColumn(Matrix.java:67)
at WorkerThread.run(WorkerThread.java:15)begin print matrix
end print matrix
source to share
Yes, the problem is that increaseRow
you are calling monitor.signal()
without blocking lock
. From the documentation for Condition.signal()
:
An implementation can (and usually) require the current thread to hold the lock associated with this Condition when this method is called. Implementations should document this precondition and any action taken if the lock is not held. Typically, an exception is thrown such as
IllegalMonitorStateException
.
Both methods increaseRow
and increaseColumn
must have a structure
lock.lock();
try {
// code including monitor.signal() here
} finally {
lock.unlock();
}
how your methods do it sumRow
, sumColumn
and printMatrix
. In addition, you can have a separate monitor (and conditions) for each row and for each column. You basically need to consider all your concurrency constraints - it's hard to give more guidance without thinking about what you're trying to achieve.
source to share
In methods increaseRow(int)
and increaseColumn(int)
you need to lock the lock on lock
, otherwise you cannot callmonitor.signal()
lock.lock();
try {
....
monitor.signal();
} finally {
lock.unlock();
}
From the docs for signal
An implementation can (and usually) require the current thread to hold the lock associated with this Condition when this method is called.
and then for ReentrantLock :
If this lock is not held when any of the wait or signaling methods are called, then an IllegalMonitorStateException is thrown.
source to share