java中的多线程(两个线程广泛使用notify()和wait())

时间:2012-08-02 14:14:41

标签: java multithreading notify

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

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

这让我有点失望:当代码已经在同步块中时,如果对象(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();
            }
        }
    }

3 个答案:

答案 0 :(得分:3)

您正在尝试通知等待您当前未持有的其他锁的线程。 错误是合理的。您对对象c进行了锁定,然后通知其他线程有关当前对象的锁定。

答案 1 :(得分: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,这一点非常重要,否则您将陷入僵局。

答案 2 :(得分: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();

如果您没有尝试使用两个线程来执行更快/更简单的操作,那么这将更加简单。