本帖最后由 java2000_net 于 2008-07-11 05:15:37 编辑

解决方案 »

  1.   

    此回复为自动发出,仅用于显示而已,并无任何其他特殊作用
    楼主【tteesstt】截止到2008-07-10 19:39:17的历史汇总数据(不包括此帖):
    发帖的总数量:97                       发帖的总分数:5700                     每贴平均分数:58                       
    回帖的总数量:62                       得分贴总数量:5                        回帖的得分率:8%                       
    结贴的总数量:97                       结贴的总分数:5700                     
    无满意结贴数:0                        无满意结贴分:0                        
    未结的帖子数:0                        未结的总分数:0                        
    结贴的百分比:100.00%               结分的百分比:100.00%                  
    无满意结贴率:0.00  %               无满意结分率:0.00  %                  
    敬礼!
      

  2.   

    你的lock都没定义啊,竟然编译过去了?
      

  3.   


    他那 lock 在 MyTest 中:static volatile Boolean lock = true;
      

  4.   

    奇怪,我刚才特意测试了一下,如果那个lock和条件分开,则可以,否则不行。
    public class MyTest {
      public static void main(String[] args) throws Exception {
        new TestThread().start();
        new TestThread().start();
        Thread.sleep(1000);
        System.out.println("Doing something...");
        synchronized (lock) {
          lock.notifyAll();
          lock.wait();
          condition = true; // 语句1
          lock.notifyAll(); // 语句2
        }
        System.exit(0);
      }  static volatile Object lock = new Object();  static volatile Boolean condition = false;;
    }class TestThread extends Thread {
      @Override
      public void run() {
        synchronized (MyTest.lock) {
          while (!MyTest.condition) {
            try {
              MyTest.lock.wait();
              System.out.println(getId());
              MyTest.lock.notifyAll();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
          System.out.println(getId());
        }
      }
    }不过我也不清楚为何条件和锁用一个对象为何不行?难道???????那个赋值的问题,lock = false; // 语句1重新生成了一个新的对象吗???造成锁异常我去测试看看!!
      

  5.   

    我用了一个可以修改内容的类,StringBuilder,同时使用了新的判断条件.length()==0;
    public class MyTest {
      public static void main(String[] args) throws Exception {
        new TestThread().start();
        new TestThread().start();
        Thread.sleep(1000);
        System.out.println("Doing something...");
        synchronized (lock) {
          lock.append(1); // 语句1
          lock.notifyAll(); // 语句2
        }
      }  static volatile StringBuilder lock = new StringBuilder();;
    }class TestThread extends Thread {
      @Override
      public void run() {
        synchronized (MyTest.lock) {
          while (MyTest.lock.length() == 0) {
            try {
              MyTest.lock.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
          System.out.println(getId());
        }
      }
    }问题难道真的是那个吗?
      

  6.   


        public static final Boolean TRUE = new Boolean(true);    public static final Boolean FALSE = new Boolean(false);    public static Boolean valueOf(boolean b) {
            return (b ? TRUE : FALSE);
        }lock = false; 不会生成新对象,应该是这儿的原因。
      

  7.   

    lock = false; //这句已经改变了 lock 的引用
    lock.notifyAll(); //再通知也没用
      

  8.   

    应该就是赋值的问题!
    查看Object类的源代码,关于notifyAll的说明指向去参考notify的说明,里面说道:
    This method should only be called by a thread that is the owner of this object's monitor
    是对象的monitor有三种方式:
         * <li>By executing a synchronized instance method of that object. 
         * <li>By executing the body of a <code>synchronized</code> statement 
         *     that synchronizes on the object. 
         * <li>For objects of type <code>Class,</code> by executing a 
         *     synchronized static method of that class. 
    这个赋值与Java的对象类型有关,当对一个Boolean赋值为一个boolean型值时,导致原来的lock
    所指的对象成为了一个新的boolean的包装类,这样前面的synchronized(lock)就失效了,所以报
    除了异常,尝试下面的例子,我们对一个Object调用了一系列的方法来做,lock指向的对象并没有发生
    变化,所以synchronized仍然有效,就不会报错了,不过,只是觉得好像是这样,呵呵。
    请尝试一下的代码,运行无误public class MyTest {
      public static void main(String[] args) throws Exception {
        new TestThread().start();
        new TestThread().start();
        Thread.sleep(1000);
        System.out.println("Doing something...");
        synchronized (lock) {
         lock.setIII(2);
         lock.notifyAll();
        }
        System.exit(0);
      }  static volatile AAA lock = new AAA(1);
    }class TestThread extends Thread {
      @Override
      public void run() {
        synchronized (MyTest.lock) {
          while (MyTest.lock.getIII()==1) {
            try {
              MyTest.lock.wait();
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
          }
          System.out.println(getId());
        }
      }
    }
    class AAA {
    int iii;
    public AAA(int i){
    iii = i;
    }
    public void setIII(int i){
    iii = i;
    }
    public int getIII(){
    return iii;
    }
    }
      

  9.   

    肯定是赋值问题,赋值之后新建了一个lock对象,赋值完毕notifyAll回到两个线程的wait方法继续走,while循环推出,然后接着马上要推出sychronized块,这个时候lock对象的MonitorState异常所以程序退出了因为每次进入sychronized块要获得对象的monitor并计数加1,退出的时候计数减1,如果这个计数对不上就会报错!
      

  10.   


    看源码,不会创建新 Boolean 对象。
      

  11.   

    始终是两个分别包装了 true 和 false 的 Boolean 在那儿折腾。
      

  12.   

    lock = false; //这句已经改变了 lock 的引用
    lock.notifyAll(); //再通知也没用
      

  13.   

    自动装箱导致的对象变动值为 true 的 Boolean 对象监视范围内并没有进行等待的线程,
    所以就抛出了 IllegalMonitorStateException 的异常。只要把改变值之前的 lock 引用对象再赋给一个临时的变量,由
    这个临时变量来通知就行了,呵呵。    synchronized (lock) {
            Boolean b = lock;
            lock = false;
            b.notifyAll();
        }
      

  14.   

    晕,写错了,更正!值为 true 的 Boolean 对象监视范围内并没有进行等待的线程,改为:值为 false 的 Boolean 对象监视范围内并没有进行等待的线程,
      

  15.   

    对于布尔对象来说,甚至可以改成:    synchronized (lock) {
            lock = false;
            Boolean.TRUE.notifyAll();
        }
      

  16.   


    那么到底有没有两个Boolean对象呢?
    我认为值为true和值为false的Boolean对象分别拥有自己的Monitor(监视器),所以正如火龙果前辈说的,为false的Boolean对象监视器替换掉true的监视器之后,无法退出sychronized块,因为曾经读过JVM官方规范:每次进入sychronized块监视器计数要加1,退出的时候要减1,如果最终为0才能正常退出,否则抛出MonitorState异常。而当初进入sychronized加1的是true的Boolean对象的监视器,退出的时候计数减1的却是为false的Boolean的监视器
      

  17.   

    synchronized (lock) {
            lock = false;
            lock.notifyAll();
        }
    所有的封装类都是只读的,所以 lock = false; 将返回一个新的对象,而当前线程获得的是原对象的锁,
    所以在新的lock对象上调用notifyAll导致IllegalMonitorStateException,与另外两个线程无关,
    如果一个线程没有获得某个对象的锁而调用它的notifyAll将导致IllegalMonitorStateException。
             个人理解,望指证。
      

  18.   

    他用的包装类 Boolean,会改变引用.直接锁 Boolean.class试试,应该不会出异常.
      

  19.   


    更正,还是会出现异常,原因,对象不同.控制台输出赋值前后的 hashcode 为:Doing something...
    1231
    1237
      

  20.   

    学习 false和true应该是2个对象
      

  21.   

    static volatile Boolean lock = true;
    lock已经同步  这个volatile不用加吧
      

  22.   

    lock.notifyAll();  这句十分不解谁解释解释`~
      

  23.   

      lock = false; // 语句1
      lock.notifyAll(); // 语句2
    这种情况下,必然出错阿lock已经是一个新对象了,而lock.notifyAll()在新对象上没有被同步。所以current thread not owner。
    换个顺序以后,在原来对象上notifyAll()了lock才变成新对象,所以没有错了
      

  24.   

    object的notify, notifyall, wait方法必须是被synchronize的,如果一个新对象没有被synchronize的时候调用这些方法就
    会current thread not owner。比如楼主问得
      

  25.   

    我在写一个程序的时候也出现类似问题:
    参见http://topic.csdn.net/u/20080710/18/9e9cdcfd-1b8c-4203-b6ba-27a2d8b8b2df.html
            synchronized (GlobalControl.isEnd) { 
                GlobalControl.isEnd=true; 
                GlobalControl.isEnd.notify(); 
            } 中,GlobalControl.isEnd=true;将使得GlobalControl.isEnd指向一个与 
    synchronized (GlobalControl.isEnd) 截然不同的对象,当然出问题了。
    Exception in thread "pool-1-thread-20" java.lang.IllegalMonitorStateException 
    at java.lang.Object.notify(Native Method) 
    at thread1.ParaNull.LogicalProcess.run(LogicalProcess.java:367) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:885) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907) 
    at java.lang.Thread.run(Thread.java:619) 
    错误
      

  26.   

    JAVA的多线程的确很累,太多细节的东西
      

  27.   

     Thread.sleep(1000);
    会产生中断异常
      

  28.   

    老紫竹真是高手,lock=new object();
    当lock要成为boolean时,是要申明成look=new Boolean(Boolean.FALSE);
      

  29.   

    我们在搞线程开发前,应该好好学习一下IBM developerwork上面已有的一些东西
    不要重新分配被锁定对象的对象引用
    developerWorks


    Peter Haggar, 高级软件工程师, IBM2000 年 10 月 01 日    编者按:编者按:本文是从“Practical Java”( Addison-Wesley 出版)一书节选而来的。您可以从 Borders.com 订购该书。请阅读我们对作者 Peter Haggar 的 采访。synchronized 关键字锁定对象。对象是在 synchronized 代码内部被锁定的,这一点对此对象以及您对其对象引用所作的更改意味着什么呢?对一个对象作同步处理只锁定该对象。但是,必须注意不要重新分配被锁定对象的对象引用。那么如果这样做会发生什么情况呢?请考虑下面这段代码,它实现了一个 Stack:class Stack
    {
      private int StackSize = 10;
      private int[] intArr = new int[stackSize];
      private int index;          //Stack 中的下一个可用位置。
      public void push(int val)
      {
        synchronized(intArr) {
          //如果已满,则重新分配整数数组(即我们的 Stack)。
          if (index == intArr.length)
          {
            stackSize *= 2;
            int[] newintArr == new int[stackSize];
            System.arraycopy(intArr, 0, newintArr, 0, intArr.length);
            intArr = newintArr;
          }
          intArr[index] == val;
          index++;
        }
      }
      public int pop()
      {
        int retval;
        synchronized(intArr) {
          if (index > 0)
          {
            retval = intArr[index-1];      //检索值,
            index--;                       //并使 Stack 减少 1 个值。
            return retval;
          }
        }
        throw new EmptyStackException();
      }
      //...
    }
    这段代码用数组实现了一个 Stack。创建了一个初始大小为 10 的数组来容纳整数值。此类实现了 push 和 pop 方法来模拟 Stack 的使用。在 push 方法中,如果数组中没有更多的空间来容纳压入的值,则数组被重新分配以创建更多的存储空间。(故意没有用 Vector 来实现这个类。 Vector 中不能储存基本类型。)请注意,这段代码是要由多个线程进行访问的。push 和 pop 方法每次对该类的共享实例数据的访问都是在 synchronized 块内完成的。这样就保证了多个线程不能并发访问此数组而生成不正确的结果。这段代码有一个主要的缺点。它对整数数组对象作了同步处理,而这个数组被 Stack 类的 intArr 所引用。当 push 方法重新分配此整数数组时,这个缺点就会显露出来。当这种情况发生时,对象引用 intArr 被重新指定为引用一个新的、更大的整数数组对象。请注意,这是在 push 方法的 synchronized 块执行期间发生的。此块针对 intArr 变量引用的对象进行了同步处理。因此,在这段代码内锁定的对象不再被使用。请考虑以下的事件序列:   1. 线程 1 调用 push 方法并获得 intArr 对象的锁。   2. 线程 1 被线程 2 抢先。   3. 线程 2 调用 pop 方法。此方法因试图获取当前线程 1 在 push 方法中持有的同一个锁而阻塞。   4. 线程 1 重新获得控制并重新分配数组。 intArr 变量现在引用一个不同的变量。   5. push 方法退出并释放它对原来的 intArr 对象的锁。   6. 线程 1 再次调用 push 方法并获得新 intArr 对象的锁。   7. 线程 1 被线程 2 抢先。   8. 线程 2 获得旧 intArr 对象的对象锁并试图访问其内存。现在线程 1 持有由 intArr 引用的新对象的锁,线程 2 持有由 intArr 引用的旧对象的锁。因为两个线程持有不同的锁,所以它们可以并发执行 synchronized push 和 pop 方法,从而导致错误。很明显,这不是所希望的结果。这个问题是因 push 方法重新分配被锁定对象的对象引用而造成的。当某个对象被锁定时,其他线程可能在同一个对象锁上被阻塞。如果将被锁定对象的对象引用重新分配给另一个对象,其他线程的挂起锁则是针对代码中已不再相关的对象的。您可以这样修正这段代码,去掉对 intArr 变量的同步,而对 push 和 pop 方法进行同步。通过将 synchronized 关键字添加为方法修饰符即可实现这一点。正确的代码如下所示:class Stack
    {
      //与前面相同...
      public synchronized void push(int val)
      {
        //如果为空,则重新分配整数数组(即我们的 Stack)。
        if (index == intArr.length)
        {
          stackSize *= 2;
          int[] newintArr = new int[stackSize];
          System.arraycopy(intArr, 0, newintArr, 0, intArr.length);
          intArr = newintArr;
        }
        intArr[index]= val;
        index++;
      }
      public synchronized int pop()
      {
        int retval;
        if (index > 0)
        {
          retval = intArr[index-1];
          index--;
          return retval;
        }
        throw new EmptyStackException();
      }
    }
    这个修改更改了实际上获取的锁。获取的锁是针对为其调用方法的对象的,而不是锁定 intArr 变量所引用的对象。因为获取的锁不再针对 intArr 所引用的对象,所以允许代码重新指定 intArr 对象引用。
    关于作者 Peter Haggar 是 IBM 的高级软件工程师。他目前正在研究新兴的 Java 和因特网技术,并且是 IBM 实时 Java 参考实现的项目主持人。他有丰富的编程经验,从事过开发工具、类库和操作系统等方面的工作。在许多行业研讨会上,他也经常就 Java 和其他技术作技术性发言。他于 1987 年在纽约获得 Clarkson 大学计算机科学学士学位。可以通过 [email protected] 与他联系