【问题标题】:How Java manage following scenario?Java如何管理以下场景?
【发布时间】:2013-11-26 07:07:44
【问题描述】:

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

我的时钟对象。

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 如何处理这种情况?

【问题讨论】:

    标签: java multithreading synchronized


    【解决方案1】:

    synchronized 块是可重入的

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

    重入有什么用?

    简单的答案是递归

    考虑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
    

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

    【讨论】:

      【解决方案2】:

      由于您的锁对象是静态的,因此它在线程之间共享。一旦线程 A 获得了锁,当线程 B 进入示例类的方法 B 时,它会尝试获取线程 A 拥有的相同的锁,因此不会出现死锁。

      问题可能出在线程 A 试图获取它在方法 B 中已经持有的锁的位置,但是在您的情况下这并没有发生,因为同步块本身是可重入的,但是如果您已经实现了自己的锁类并且如果您没有被拒绝出租,就会出现死锁。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-03
        • 2020-05-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-03-30
        相关资源
        最近更新 更多