线程并发 - 同步和锁定。

时间:2011-12-26 14:06:38

标签: java multithreading concurrency scjp ocpjp

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中使用的锁不同的锁上被调用。

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

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

1 个答案:

答案 0 :(得分:2)

执行时

sa = new String("Done");

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

这意味着您在sa上同步(第一个对象:“Not Done”),然后将新对象分配给sa(第二个对象:“Done”),并在第二个对象上调用notify。由于您没有同步第二个对象,但是在第一个对象上,您会收到IllegalMonitorException。仅当您拥有对象的内部锁定时,才允许在对象上调用通知。这就是锁定永远是最终的原因。

调用notify()等同于调用this.notify()。因此this.notify()sa.notify()只是在两个不同的对象上调用notify()。第一个将通知等待this的线程,第二个将通知等待sa的线程。

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