Java synchronized String IllegalMonitorStateException

时间:2014-07-21 08:55:56

标签: java multithreading blackberry

我试图让Thread2等待String和Thread1在String更新时通知,我按照下面的代码显示同步String对象,但我仍然得到IllegalMonitorStateException这里' s我的代码

public class Class1{

String string   = "";

public Class1(){


    Thread t1   = new Thread(){

        public void run(){

            synchronized(string){

                string = "Something"; string.notifyAll();   //This is the line that throws an IllegalMonitorStateException
            }

        }

    };


    Thread t2   = new Thread(){

        public void run(){

            synchronized(string){

                try{

                    string.wait();

                }catch(Exception e){

                    e.printStackTrace();

                }

            }

        }

    };

    t2.start();
    t1.start();
}

}

除了突出显示string.notifyAll()

之外,StackTrace中没有任何内容

1 个答案:

答案 0 :(得分:3)

  1. 您的代码包含数据争用,因为它访问string块之外的可变synchronized变量。具体而言,这发生在synchronized(string)行上。取消引用string以访问其监视器将被锁定的对象时,该线程尚未锁定该对象。因此,您无法保证它将获得锁定的对象。

  2. mutate string变量的事实意味着它现在指向其他一些对象。当下一个线程获得对该新对象的锁定时,它将不会受益于任何发生在之前的关系,因为它是第一个获得锁定的线程。也不保证相互排斥,因为可能存在任意多个线程,每个线程在没有争用的情况下锁定不同的String实例。

  3. 结合上述两种现象,我们也可以看到,无法保证在synchronized(string)行上到达的对象与在中从到达的对象相同>同步块。一旦发生这确实是一个不同的对象,您的IllegalMonitorStateException就会发生。

  4. 总之,情况非常类似于根本不存在的synchronized块。

    如果您始终遵循使用专用final变量来引用用于锁定的对象的最佳实践,则可以避免上述所有问题。简而言之,在您的示例中修复编译错误,这就是您必须编写的内容:

    static String string = "";
    static final Object lock = new Object();
    
    public static void main(String[] args) {
      Thread t1 = new Thread() {
        public void run() {
          synchronized (lock) {
            ... update the string variable ...
            lock.notifyAll();
          }
        }
      };
      Thread t2 = new Thread() {
        public void run() {
          synchronized (lock) {
            try {
              lock.wait();
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        }
      };
      t2.start();
      t1.start();
    }