0

当我尝试运行以下程序时,在这段代码中第一次调用 notify() 时会出现 IllegalMonitorStateException:

synchronized (c) {
    try {
        notify();
        ....

这让我有点不知所措:当对象(c)已经在同步块中时,代码怎么可能不对对象(c)进行锁定,检查相同的锁?

请不要介意过度使用 notify() 和 wait() 看起来有些奇怪。我知道有不同的(更有效的)实现可以执行相同的任务,但现在我正试图弄清楚为什么这个特定的实现不起作用。

完整代码如下:

  class J implements Runnable {

        public static void main(String[] x) {
            Calc calc = new Calc();
            J j = new J(calc);
            Thread t1 = new Thread(j, "one");
            Thread tCalc = new Thread(calc, "Calc");
            tCalc.start();
            t1.start();
        }
        Calc c;
        public J(Calc c) {
            this.c = c;
        }

        public void run() {
            synchronized (c) {
                try {
                    notify();
                    c.wait();
                } catch (InterruptedException e) {

                }
                System.out.println(Thread.currentThread().getName() + ": x = "
                        + c.getX());
                notify();
            }
        }
    }

    class Calc implements Runnable {

        private int x;

        public int getX() {
            return x;
        }

        public void run() {
            synchronized (this) {

                for (int x = 1; x <= 11111; x *= (x + x)) {
                    this.x += x;
                    try {
                        notify();
                        this.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                notify();
            }
        }
    }
4

3 回答 3

3

您正在尝试通知等待您当前未持有的不同锁的线程。错误是有道理的。您在对象 c 上有一个锁,然后您通知其他线程有关当前对象上的锁。

于 2012-08-02T14:18:49.903 回答
1
synchronized (c) {
    try {
        notify();
        ....

您正在锁定对象c,但您正在通知对象this。始终明确指定您在哪个对象上是一个很好的wait()做法notify()。你应该做:

synchronized (c) {
    try {
        c.notify();
        ....

或者:

synchronized (this) {
    try {
        this.notify();
        ....

看起来您实际上是要处理 2 个锁。如果是这种情况,那么您将执行以下操作。

synchronized (c) {
    try {
        synchronized (this) {
            this.notify();
        }
        c.wait();

重要的是要确保始终c先锁定,this否则将死锁。

于 2012-08-02T14:20:26.913 回答
0

您所拥有的是执行以下操作的复杂方法。

ExecutorService printer = Executors.newSingleThreadExecutor();

int x2 = 0;
for (int x = 1; x <= 11111; x *= (x + x)) {
    x2 += x;
    final int x3 = x2;
    printer.submit(new Runnable() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + ": x = " + x3);
        }
    });
}
printer.shutdown();

如果您不尝试使用两个线程来做一些更快/更简单的事情,这将更加简单。

于 2012-08-02T14:50:35.353 回答