为什么不造成僵局?

时间:2014-10-29 11:08:54

标签: java multithreading locking deadlock

请参阅以下代码

package com.test;

public class DeadLock {

    private void method1() {

        synchronized (Integer.class) {
            method2();
        }
    }

    private void method2() {
        synchronized (Integer.class) {
            System.out.println("hi there");
        }
    }

    public static void main(String[] args) {
        new DeadLock().method1();
    }
}

根据我的理解,method2中的代码不应该在任何情况下执行,因为method1持有Integer.class上的锁,method2尝试访问锁定再次Integer.class。但令我惊讶的是,代码运行良好,并在控制台上打印“hi there”。有人可以澄清吗?

5 个答案:

答案 0 :(得分:4)

锁是由线程拥有的。如果你的线程已经拥有一个锁,那么Java假定你不需要再次获取它而只是继续。

如果在保持锁定的同时在method1()中启动第二个线程并且第二个线程执行方法method2(),则会出现死锁。

如果您更喜欢代码,那么synchronized的工作原理如下:

Lock lock = Integer.class.getLock();
boolean acquired = false;
try {
    if(lock.owner != Thread.currentThread()) {
        lock.acquire();
        acquired = true;
    }

    ...code inside of synchronized block...
} finally {
    if(acquired) lock.release();
}

这是演示死锁的代码。只需将runInThread设置为true

即可
package com.test;

public class DeadLock {

    private void method1() {

        synchronized (Integer.class) {
            boolean runInThread = false;

            if( runInThread ) {
                Thread t = new Thread() {
                    @Override
                    public void run() {
                        method2();
                    }
                };
                t.start();
                try {
                    t.join(); // this never returns
                } catch( InterruptedException e ) {
                    e.printStackTrace();
                }
            } else {
                method2();
            }
        }
    }

    private void method2() {
        System.out.println("trying to lock");
        synchronized (Integer.class) {
            System.out.println("hi there");
        }
    }

    public static void main(String[] args) {
        new DeadLock().method1();
    }
}

答案 1 :(得分:3)

似乎你误解了这个概念。 方法永远不会获取锁,调用该方法的实例在同步方法的情况下用作锁,在同步块的情况下,线程获取对指定对象的锁。

这里实例获取Integer.class上的锁,然后继续执行method2。

没有死锁的情况,因为你的情况下线程继续执行你在method1中调用的方法。所以没有发生死锁。

答案 2 :(得分:0)

您的代码相当于:

synchronized (Integer.class) {
    synchronized (Integer.class) {
        System.out.println("hi there");
    }
}

如果线程获得了锁并进入了第一个synchronized块,那么访问第二个

就没有问题了

产生死锁,对method2的调用应该由不同的线程执行。

答案 3 :(得分:0)

 synchronized (Integer.class) {
            method2();
        }

当你调用这个method2();时它没有锁定任何类型的mehtod,它继续转到你正在调用的方法意味着这个。

private void method2() {
        synchronized (Integer.class) {
            System.out.println("hi there");
        }
    }

并在完成返回后。所以没有死锁的情况。希望这个解释有所帮助。

答案 4 :(得分:0)

如前所述,当没有其他线程已经阻止它时,一个线程可以访问多个同步块。在那种情况下,同一个线程可以重新输入synchronized块,因为它已经从method1保存它。

要导致死锁,您必须至少使用两个线程和两个不同的锁。它必须以相反的顺序访问两个锁。看看代码:

private void method1() throws InterruptedException
{
    synchronized (Integer.class)
    {
        System.out.println(Thread.currentThread().getName() + " hi there method 1");
        Thread.sleep(1000);
        method2();
    }
}

private void method2() throws InterruptedException
{
    synchronized (Double.class)
    {
        System.out.println(Thread.currentThread().getName() + " hi there method 2");
        Thread.sleep(1000);
        method1();
    }
}

public static void main(String[] args) throws InterruptedException
{
    new Thread()
    {
        @Override
        public void run()
        {
            try
            {
                new DeadLock().method1();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }.start();
    new DeadLock().method2();
}
相关问题