Java如何管理以下场景?

时间:2013-11-26 07:07:45

标签: java multithreading synchronized

我尝试了一些代码来证明同步块锁定机制的可靠性。考虑我的示例代码

我的时钟对象。

public class MyLock {
final static Object lock=new Object();
}

具有同步块的类

public class Sample {

public void a(String input) {
    System.out.println(input+" method a");
    synchronized (lock) {
        System.out.println("inside synchronized block in a");
        try {
            System.out.println("waiting in a");
            Thread.sleep(5000);
            System.out.println("calling b() from a");
            new Sample().b("call from a");
            System.out.println("waiting again in a");
            Thread.sleep(5000);
            System.out.println("Running again a");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public void b(String input) {
    System.out.println(input+" method b");
    synchronized (lock) {
        System.out.println("bbb " + input);
    }
 }

}

Test1类

public class Test1 implements Runnable{

public static void main(String[] args) {
   new Thread(new Test1()).start();
   new Thread(new Test2()).start();
}

@Override
public void run() {
   new Sample().a("call from main");
 }
}

Test2类

public class Test2 implements Runnable {
@Override
public void run() {
   new Sample().b("call from main");
 }
}

我刚刚这样做是因为我认为如果持有锁的同一线程女巫将使用相同的锁来锁定其他方法,那么将会出现死锁情况。现在考虑输出

call from main method a
call from main method b
inside synchronized block in a
waiting in a
calling b() from a // i thought this will cause a dead lock
call from a method b
bbb call from a
waiting again in a
Running again a
bbb call from main 

现在你可以看到没有这样的问题。我的问题是Java如何处理这种情况?

2 个答案:

答案 0 :(得分:6)

synchronized阻止是可重入的

默认情况下,synchronized块中使用的锁定(互斥锁准确)是 Reentrant ,这意味着如果同一个线程尝试再次获得相同的锁,它将不必等待,并将立即进入关键区块,因为它已经拥有该锁定。

Reentrancy在哪里有用?

简单回答是 递归

考虑synchronized方法递归的场景,

int synchronized method(int param){
   //... some logic

   method(param - 1);
}

在此示例中,您不希望为同一个锁阻止相同的线程,因为它永远无法继续。

在这种情况下发生死锁:

Thread A acquires lock A
Thread B acquires lock B
Thread A tries to acquire lock B
Thread B tries to acquire lock A

现在在这种情况下,没有人能够继续进行并因此陷入僵局。但是在你的场景中只有一个锁,所以另一个线程只是等待第一个线程离开锁然后再继续。

答案 1 :(得分:0)

由于您的锁对象是静态的,因此它在线程之间共享。一旦线程A获得了锁,并且线程B进入样本类的方法B,它就会尝试获取由线程A拥有的相同锁。因此不存在死锁的可能性。

问题可能出在线程A试图获取它已经在方法B中保存的锁的情况,但是在你的情况下这并没有发生,因为synchnorized块本身是重新输入但是如果你已经实现了自己的锁类并且你不会为了逃避原因,将会有一个死锁。