i' m working in a multithreading program. The threads are working in a matrix (workerThread) and i have got a thread (display) that print the matrix state.i' m getting this exception, inside the increaseRow() of Matrix class at the line monitor.signal()
can someone tell me, what's 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();
}
}
the 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();
}
}
the 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
Yes, the problem is that in increaseRow
you're calling monitor.signal()
without having locked lock
first. From the documentation for Condition.signal()
:
An implementation may (and typically does) require that the current thread hold the lock associated with this Condition when this method is called. Implementations must document this precondition and any actions taken if the lock is not held. Typically, an exception such as
IllegalMonitorStateException
will be thrown.
Both your increaseRow
and increaseColumn
methods should have a structure of
lock.lock();
try {
// code including monitor.signal() here
} finally {
lock.unlock();
}
just as your sumRow
, sumColumn
and printMatrix
methods do. Alternatively, you may want to 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 more idea of what you're trying to achieve.
See more on this question at Stackoverflow