堆栈溢出而不是死锁

时间:2013-12-05 16:43:57

标签: java deadlock stack-overflow

输出有堆栈溢出。它背后的原因是什么? 即使我把睡眠输出重新存储与堆栈溢出错误相同?我什么时候可以在这个程序中看到死锁?

public class DeadLock extends Thread    {
    private static String o1  = new String();
    private static String o2  = new String();
    private String info;

    public DeadLock (String info) {
        this.info    = info;
    }

    private void inProtected_1 () {
        synchronized ( o2 )   {
            inProtected_2();
        }
    }

    private void inProtected_2 () {
        synchronized ( o1 )   {
            inProtected_1();
        }
    }

    public void run () {
        if ( info.equals("first") ) {
            synchronized ( o1 )   {
                inProtected_1();
            }
        } else
            synchronized ( o2 )   {
                inProtected_2();
            }
    }

    public static void main (String args []) {
        new DeadLock("second").start();
        new DeadLock("first").start();
    }
}

5 个答案:

答案 0 :(得分:1)

在Java中,synchronized锁是可重入的。

因此,您的第一个线程获取o1上的锁定以及o2上的锁定并保持循环。这就是你获得StackOverFlow的原因。第二个线程只是等待第一个锁。

要实际获得死锁,请在方法中添加sleep,以便两个线程都能获得一个锁:

private void inProtected_1 () {
    synchronized (o2) {
        Thread.sleep(1000);    // simulate work
        inProtected_2();
    }
}

private void inProtected_2 () {
    synchronized (o1)   {
        Thread.sleep(1000);   // simulate work
        inProtected_1();
    }
}

此外,为确保不要在实际的同一对象上进行同步,请使用new Object()代替new String()

答案 1 :(得分:0)

synchronized(o1)方法中执行run()后,您可以立即进行上下文切换。在上下文切换之后,您将拥有持有o1的线程1和持有o2的线程2。当任何一个尝试在相反的o值上进行同步时,都会导致死锁。每个同步操作都需要另一个锁。

另外,尽量不要使用同步,你应该使用实际的Lock个对象。

答案 2 :(得分:0)

启动的第一个线程可以想象得到两个锁。然后它会调用自己很多次,你会得到一个堆栈溢出,而另一个线程只是坐在那里等待锁定。如果将print语句添加到打印出'info'变量的方法之一,您可能会看到每行打印出相同的信息。

答案 3 :(得分:0)

是的,您应该使用sleep来获得更多保证死锁。例如,它会在我的机器上创建死锁:

public class DeadLock1 extends Thread    {
    private static String o1  = new String();
    private static String o2  = new String();
    private String info;

    public DeadLock1 (String info) {
        this.info    = info;
    }

    private void inProtected_1 () {
        synchronized ( o2 )   {
            try {
                Thread.sleep(100);
            } catch (Exception e) {

            }
            inProtected_2();
        }
    }

    private void inProtected_2 () {
        synchronized ( o1 )   {
            try {
                Thread.sleep(100);
            } catch (Exception e) {

            }
            inProtected_1();
        }
    }

    public void run () {
        if ( info.equals("first") ) {
            synchronized ( o1 )   {
                inProtected_1();
            }
        } else
            synchronized ( o2 )   {
                inProtected_2();
            }
    }

    public static void main (String args []) {
        new DeadLock1("second").start();
        new DeadLock1("first").start();
    }
}

基本上我在每个线程锁定了他的字符串之后在它锁定另一个线程的字符串之前添加了睡眠。这样我保证当线程尝试锁定第二个字符串时 - 它已经锁定并且我们会死锁。

答案 4 :(得分:0)

在String上放置锁是危险的。

根据Java语言规范的第3.10.5节:

不同包中不同类中的文字字符串同样表示对同一String对象的引用。

这意味着如果另一个类包含相同的字符串文字,它将引用相同的String对象并可能导致死锁。