Java Threads同步意外输出

时间:2014-10-11 04:35:57

标签: java multithreading synchronized

我正在攻读OCPJP考试并且很难理解线程。特别是,我在下面列出了这个程序。当我运行这个程序时,我得到以下输出,这让我很困惑。

Inside push method...
Inside push method now sleeping...
Exit from main()
Inside push method stopped sleeping...
Exiting push method...
Pushed: true
Popped: 2008
Inside push method...
Inside push method now sleeping...
Inside push method stopped sleeping...
Exiting push method...
Pushed: true
Inside push method...
Inside push method now sleeping...
Inside push method stopped sleeping...
Exiting push method...
Pushed: true
Popped: 2008
Inside push method...
Inside push method now sleeping...
Popped: 2008

得到我的是输出的最后一行。 api说,当调用sleep时,线程不会失去任何监视器/锁的所有权。如何以下:

Inside push method now sleeping...
Popped: 2008
可以发生,因为我们进入synchronized方法push(),push()有监视器/锁定,为什么我们能够执行pop()方法push()正在睡觉?我需要帮助,有人可以给出一个易于理解的解释吗?

class StackImpl {                   //(1)


private Object[] stackArray;
private int topOfStack;

public StackImpl(int capacity){
    stackArray = new Object[capacity];
    topOfStack = -1;
}

//  public boolean push(Object element){                                    //(2a) non-synchronized
public synchronized boolean push(Object element){                   //(2b) synchronized
    if(isFull()) return false;
    System.out.println("Inside push method...");
    ++topOfStack;
    try{
        System.out.println("Inside push method now sleeping...");
        Thread.sleep(10000);
        System.out.println("Inside push method stopped sleeping...");} catch(Exception e){}                 //(3) Sleep a little
    stackArray[topOfStack] = element;
    System.out.println("Exiting push method...");
    return true;

}


//public Object pop(){                                              //(4a) non-synchronized
public synchronized Object pop(){                                   //(4b) synchronized
    if(isEmpty()) return null;
    Object obj = stackArray[topOfStack];
    stackArray[topOfStack] = null;
    try{Thread.sleep(1000);}catch(Exception e){}                        //(5) Sleep a little
    topOfStack--;
    return obj;

}

public boolean isEmpty(){return topOfStack < 0;}
public boolean isFull(){return topOfStack >= stackArray.length - 1;}


}


public class Mutex{
public static void main(String[] args) throws InterruptedException {

    final  StackImpl stack = new StackImpl(20);                     //(6) Shared by the threads

    (new Thread("Pusher"){                                          //(7) Thread no. 1  
        public void run(){
            for(;;){
                System.out.println("Pushed: " + stack.push(2008));
            }
        }
    }).start();

    // make sure Thread no.1 goes first
    Thread.sleep(2000);

    (new Thread("Popper"){                                          //(8) Thread no.2
        public void run(){
            for(;;){
                System.out.println("Popped: " + stack.pop());
            }
        }
    }).start();


    System.out.println("Exit from main()");



}
}

1 个答案:

答案 0 :(得分:1)

输出是一致的,但它并不直接与堆栈上的操作相对应(对printlnpop / push的单独调用不是原子的)。在Java中,您不能在Thread.sleep(n)中释放显示器上的锁定是正确的(但Object.wait()并非如此)。

要查看实际的顺序,您可以修改放入堆栈的内容......

final  StackImpl stack = new StackImpl(20);                     //(6) Shared by the threads


(new Thread("Pusher"){                                          //(7) Thread no. 1

    public void run(){

    int i = 0;

        for(;;){
            System.out.println("Pushed: " + stack.push(i++));
        }
    }
}).start();

现在你应该可以看到哪个推送对应哪个pop。