0
import java.util.*;
import java.io.*;
import java.util.regex.*;

class ZiggyTest2 extends Thread{

    String sa;

    public ZiggyTest2(String sa){
        this.sa = sa;
    }

    public void run(){
        synchronized(sa){
            while(!sa.equals("Done")){
                try{
                    sa.wait();
                }catch(InterruptedException is){System.out.println("IE Exception");}
            }
        }

        System.out.println(sa);
    }
}

class Test{
    private static String sa = new String("Not Done");

    public static void main(String[] args){
        Thread t1 = new ZiggyTest2(sa);
        t1.start();

        synchronized(sa){
            sa = new String("Done");
            sa.notify();
        }
    }
}

当我运行上述程序时,我得到以下异常:

Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notify(Native Method)
        at Test.main(ZiggyTest2.java:35)

几个问题:

  • 为什么会出现 IllegalMonitorStateException?因为 Test.sa 被分配给一个新的 String 对象,我期待 ZiggyTest2 线程无限期地等待,因为 sa.notify() 将在与 ZiggyTest2 中使用的锁不同的锁上调用。

  • 在上面的示例中,在“sa”对象上调用了 wait() 和 notify()。说自己调用 notify() 和使用对象即 sa.wait() 和 sa.notify() 调用 notify()/wait() 有什么区别?

  • 在 Test 类中同步块具有 sa 对象的锁并且 sa 对象是静态的但在 ZiggyTest2 类中,同步块使用相同的 sa 对象引用但使用非静态引用是否重要?鉴于一个是静态的而另一个不是,他们是否仍然使用同一个锁?

4

1 回答 1

2

当你执行

sa = new String("Done");

您不会更改 String 引用的内容sa。您将一个新的 String 实例(一个新对象)分配给sa. 字符串是不可变的。改变它们的价值是不可能的。

这意味着您在 sa 上进行同步(第一个对象:“未完成”),然后将一个新对象分配给 sa(第二个对象:“完成”),并在第二个对象上调用 notify。由于您没有在第二个对象上同步,但在第一个对象上,您会收到 IllegalMonitorException。仅当您拥有对象的内在锁时,才允许对对象调用 notify。这就是为什么锁应该始终是最终的。

调用 notify() 等价于调用 this.notify()。所以this.notify()andsa.notify()只是调用notify()两个不同的对象。第一个将通知正在等待的线程this,第二个将通知正在等待的线程sa

变量是否是静态的这一事实并不重要。锁与对象相关联,而不是与它的引用相关联。

于 2011-12-26T14:52:32.533 回答