调用在另一个同步内同步

时间:2015-03-19 19:27:50

标签: java multithreading synchronized

第1部分:

假设以下代码

void method1(){

    synchronized (lockObject){
        method2();
        System.out.println("line4");
    }

}

void method2(){
    System.out.println("line1");

    synchronized (lockObject){
        System.out.println("line2");
    }

    System.out.println("line3");
}

这是一个僵局吗?这是一个安全的代码吗?输出总是:

line1
line2 
line3
line4

第2部分:

如果在另一个线程上执行method2()怎么办?输出会不同吗?像这样:

void method1(){

    synchronized (lockObject){
        method2();
        System.out.println("line4");
    }

}

void method2(){
        newThread= new Thread(new Runnable() {
            @Override
            public void run() {     
                System.out.println("line1");
                synchronized (lockObject){
                    System.out.println("line2");
                }
                System.out.println("line3");
            }
        }).start();
}

我猜这第二个代码的输出可以是:

line4
line1 
line2
line3

这是对的吗?

3 个答案:

答案 0 :(得分:6)

是的,您可以在同一个对象上多次同步而不会出现死锁,它就像重入锁一样。

至于输出。第一个是简单的顺序输出,同步不会影响它。第二个将产生预期的输出,因为另一个线程将不得不等待第一个释放lockObject。

编辑,未确定line1和line4的顺序,因为之前没有同步。 line2和line3总是在line4之后,因为第二个线程无法开始打印line1,直到第一个离开method1同步块。

答案 1 :(得分:4)

第1部分:不,没有死锁,因为只有一个锁。当可以以不同的顺序获取多个锁时发生死锁。输出将始终相同。

第2部分:不存在死锁,但是打印语句的顺序可能会有所不同。第1-3行将始终以相互正确的顺序出现,但是" line4"声明可以在第1行或第2行之前打印。

如果你想阻止第1行和第2行之间出现第4行,你需要让它们显示为" atomic"通过在synchronized区块内移动它们来进行操作。

答案 2 :(得分:2)

内部锁是可重入的。即使一个帖子已经拥有它,它也可以获得一个。

来自the Oracle tutorial

  

回想一下,线程无法获取另一个线程拥有的锁。但是一个线程可以获得它已经拥有的锁。允许线程多次获取相同的锁可启用重入同步。这描述了一种情况,其中同步代码直接或间接地调用也包含同步代码的方法,并且两组代码使用相同的锁。如果没有可重入同步,同步代码必须采取许多额外的预防措施,以避免线程导致自身阻塞。

对于第二个示例,您启动的新线程必须等到对method1的调用释放锁定。在新线程启动之前,可能会对method1的调用完成,释放锁,因为启动新线程需要一段时间,但不能保证。 "第1行"可以在" line4"之前打印。对于" line2"为了打印,方法1必须先完成调用。