下面的代码在绝大部分时间内都运行得很正常,请问在什么情况下会出现问题?问题的根源在哪里?
    import java.util.LinkedList;    public class Stack {
   
        LinkedList list = new LinkedList();        public synchronized void push(Object x) {
            synchronized(list) {   
                list.addLast( x );
                notify();
            }
        }        public synchronized Object pop()
            throws Exception {   
            synchronized(list) {   
                if( list.size() <= 0 ) {
                    wait();
                }
                return list.removeLast();
            }
        }
    }

解决方案 »

  1.   

    下面是一位朋友的分,个人觉得有问题(红色),线程从wait状态转为运行状态,是重新执行,还是接着执行?--------这段代码主要问题是: 假设有两个线程(thread1,thread2) 在并行执行pop,
    假设thread1 获取了对象锁,但是list.size() <= 0,所以该线程释放对象锁,并且等待。
    有一个线程(thread3)获取对象锁,然后执行了 push,并且notify这时,thread1,和thread2都在争抢对象锁, 假设thread2抢到,那么list.size() ==1
    thread2 pop了,然后释放对象锁,这时,list.size() ==0,
    然后thread1获得对象锁, 可是它认为现在list.size() 〉0  ,结果可想而知
    -----------
      

  2.   

    是不是应该是list.notify()和list.wait()?
      

  3.   

    下面的只是猜测,因为我不知道具体出什么错。当一个线程执行下面方法:
    public synchronized void push(Object x) { 
                synchronized(list) {  
                    list.addLast( x ); 
                    notify(); 
                } 
            } 
    这个时候他获得2个锁,一个是Stack对象的锁,还有list对象的锁,而notify,释放的是stack对象的锁,没有释放list对象的锁
      

  4.   

    所以只要当pop方法中检测到list的大小为0,则执行pop的线程会一直控制list的锁,使得push没法执行。
    之所以大部分时间程序运行成功,是因为push总比pop快,list没有为0.
      

  5.   

    感觉上面每push一个对象都要notify,效率上会有问题吧.
    /**
     * 模拟栈
     * @author ybygjy
     * @date 2009-3-18
     */
    public class LinkListStack {
        /**singlon模式*/
        private static LinkListStack linkListStackObj = null;
        /**内置创建线程安全的List*/
        private LinkedList<Object> linkedList = (LinkedList<Object>) Collections.synchronizedList(new LinkedList<Object>());
        
        /**
         * Constructor 私有方法
         */
        private LinkListStack() {
            
        }
        /**
         * 得到栈实例
         * @return linkListStackObj 栈实例
         */
        public static final LinkListStack getLinkListStackInstance() {
            if (linkListStackObj == null) {
                linkListStackObj = new LinkListStack();
            }
            return linkListStackObj;
        }
        /**
         * 入栈
         * @param obj 将要入栈的实例
         */
        public synchronized void push(final Object obj) {
            linkedList.add(obj);
        }
        /**
         * 出栈
         * @return linkedList 出栈的实例
         */
        public synchronized Object pop() {
            return linkedList.removeLast();
        }
    }
      

  6.   

    public class Stack { 
      
            LinkedList list = new LinkedList();         public void push(Object x) { 
                synchronized(list) {  
                    list.addLast( x ); 
                    list.notify(); 
                } 
            }         public Object pop() 
                throws Exception {  
                synchronized(list) {  
                    if( list.size() <= 0 ) { 
                        list.wait(); 
                    } 
                    return list.removeLast(); 
                } 
            } 
        } 
      

  7.   

    楼上的朋友好
    我有一疑问,还请解答:wait()   是当前线程释放其占有的对象锁(是释放所有对象锁吗?),让其它线程得以使用这些对象;其本身进入锁等待状态
    notity() 激活线程的锁等待,使其持有锁,以便运行另外,你的答复:
    ----
    这个时候他获得2个锁,一个是Stack对象的锁,还有list对象的锁,而notify,释放的是stack对象的锁,没有释放list对象的锁
    ------
    那个notify 应该wait吗,还是就是notify
    谢谢
      

  8.   

    notify()唤醒在此对象监视器上等待的单个线程
    wait() 是等待指定对象,释放获得的指定对象的锁,所以调用哪个对象的wait方法,就等待哪个对象并释放拥有的那个对象的锁。具体怎么改8楼已经帮你改好了,能用么?
      

  9.   

    谢谢楼上的,受益了也就是说,线程间的同步是通过,notify, wait方法之间进行的,而这两个方法之间的通讯必须是同一对象间(想想也是,真晕啊), 具体哪个对象看调用该方法的对象;wait :  释放对象锁,让当前线程等待状态,直到其它线程中调用该对象的notify方法才会继续运行(不一定立刻)对于两个线程A,B 
      A中对象条件不满足时,wait;  等待B改变了该对象的条件,并notify,A接着执行以上正确不?
      

  10.   

    通常,多线程之间需要协调工作。例如,浏览器的一个显示图片的线程displayThread想要执行显示图片的任务,必须等待下载线程downloadThread将该图片下载完毕。如果图片还没有下载完,displayThread可以暂停,当downloadThread完成了任务后,再通知displayThread“图片准备完毕,可以显示了”,这时,displayThread继续执行。  以上逻辑简单的说就是:如果条件不满足,则等待。当条件满足时,等待该条件的线程将被唤醒。在Java中,这个机制的实现依赖于wait/notify。等待机制与锁机制是密切关联的。例如:synchronized(obj) { 
      while(!condition) {
      obj.wait();}  obj.doSomething();  }
     
      当线程A获得了obj锁后,发现条件condition不满足,无法继续下一处理,于是线程A就wait()。  在另一线程B中,如果B更改了某些条件,使得线程A的condition条件满足了,就可以唤醒线程A:         synchronized(obj) { 
      condition = true;  obj.notify();  }
     
      需要注意的概念是:  # 调用obj的wait(), notify()方法前,必须获得obj锁,也就是必须写在synchronized(obj) {...} 代码段内。  # 调用obj.wait()后,线程A就释放了obj的锁,否则线程B无法获得obj锁,也就无法在synchronized(obj) {...} 代码段内唤醒A。  # 当obj.wait()方法返回后,线程A需要再次获得obj锁,才能继续执行。  # 如果A1,A2,A3都在obj.wait(),则B调用obj.notify()只能唤醒A1,A2,A3中的一个(具体哪一个由JVM决定)。  # obj.notifyAll()则能全部唤醒A1,A2,A3,但是要继续执行obj.wait()的下一条语句,必须获得obj锁,因此,A1,A2,A3只有一个有机会获得锁继续执行,例如A1,其余的需要等待A1释放obj锁之后才能继续执行。  # 当B调用obj.notify/notifyAll的时候,B正持有obj锁,因此,A1,A2,A3虽被唤醒,但是仍无法获得obj锁。直到B退出synchronized块,释放obj锁后,A1,A2,A3中的一个才有机会获得锁继续执行。