调用signal()时抛出java.lang.IllegalMonitorStateException

时间:2014-10-15 13:51:43

标签: java multithreading

我正在从事多线程计划。线程在矩阵(workerThread)中工作,我有一个线程(显示)打印矩阵状态。我在行监视器的Matrix类的increaseRow()内得到此异常 。信号()

有人可以告诉我,有什么不对吗?

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();

    }
}

显示类:

    public class Display extends Thread {

        private Matrix matrix;

        public Display(Matrix matrix) {
            this.matrix = matrix;
        }

        @Override
        public void run() {
            while(true)
            matrix.printMatrix();
        }

    }

workerThread类:

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));
        }
    }

}

更新

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

2 个答案:

答案 0 :(得分:6)

是的,问题在于increaseRow您在没有先锁定monitor.signal()的情况下调用lock。来自Condition.signal()的文档:

  

当调用此方法时,实现可能(并且通常确实)要求当前线程保持与此Condition关联的锁。实现必须记录此前提条件以及未保持锁定时所采取的任何操作。通常,会抛出IllegalMonitorStateException之类的异常。

您的increaseRowincreaseColumn方法都应具有

结构
lock.lock();
try {
    // code including monitor.signal() here
} finally {
    lock.unlock();
}

就像您的sumRowsumColumnprintMatrix方法一样。或者,您可能希望为每行和每列分别设置一个监视器(和条件)。您基本上需要考虑所有的并发约束 - 如果不了解您正在尝试实现的目标,就很难提供更多指导。

答案 1 :(得分:4)

在方法increaseRow(int)increaseColumn(int)中,您需要锁定lock,否则您无法调用monitor.signal()

lock.lock();
try {
     ....
     monitor.signal();
} finally {
    lock.unlock();
}

来自signal

的文档
  

当调用此方法时,实现可能(并且通常确实)要求当前线程保持与此Condition关联的锁。

然后是ReentrantLock

  

如果在调用任何条件等待或信令方法时未保持此锁定,则抛出IllegalMonitorStateException。