首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java:当锁为null时,为什么这是一个死锁?

Java:当锁为null时,为什么这是一个死锁?
EN

Stack Overflow用户
提问于 2017-01-03 10:54:05
回答 2查看 346关注 0票数 3

我的代码中有一个死锁场景。我用下面的测试代码再现了这个场景(参见行号注释)。

我有一个ExecuterService,它需要三个任务,两个任务在同一个对象上有一个同步块,这个对象没有初始化,它应该有null值。

synchronized(null){}在java中是不允许的,所以我预期line-2会出错。但是,这是在死锁中执行的。即前两项任务在第三项任务前等待。(见产出-1)

现在,如果我将line-1更改为Object lock = new Object();,代码将完美无缺地工作,没有任何死锁(输出-2)。我只是想知道,当我们提供一个未初始化的互斥对象时,JVM到底发生了什么?看起来JVM正在为相同的任务创建一个静态副本,该副本由所有任务共享。所以死锁

代码语言:javascript
复制
public class Test {
    Object lock; //line -1
    Integer a = 10;

    public static void main(String[] arg) {
        new Test().doIt();
    }

    public void doIt() {
        ExecutorService service = Executors.newFixedThreadPool(3);

        service.submit(new Runnable() {
            public void run() {
                synchronized (Test.this.lock) { //line -2
                    try {
                        Thread.sleep(1000 * 5);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    Test.this.a = (int) Thread.currentThread().getId();
                    System.out.println(a + " " + Thread.currentThread().getId());

                }
            }
        });

        service.submit(new Runnable() {
            public void run() {
                synchronized (Test.this.lock) {
                    try {
                        Thread.sleep(1000 * 5);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    Test.this.a = (int) Thread.currentThread().getId();
                    System.out.println(a + " " + Thread.currentThread().getId());

                }
            }
        }

        );

        service.submit(new Runnable() {
            public void run() {
                Test.this.a = (int) Thread.currentThread().getId();
                while (true) {
                    try {
                        Thread.sleep(1 * 1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(a + " Main");
                }
            }
        });

    }
}

输出-1

代码语言:javascript
复制
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
11 Main
.
.
.

输出-2

代码语言:javascript
复制
11 Main
11 Main
11 Main
11 Main
9 9
9 Main
9 Main
9 Main
9 Main
9 Main
10 10
10 Main
10 Main
.
.
.
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-01-03 10:59:00

您没有死锁--正如您预期的那样,有一个错误。第一个和第二个任务将抛出NullPointerException,只剩下第三个任务在运行。

如果您在一个run() /catch语句中包围了它的主体,就可以看到这一点。

票数 8
EN

Stack Overflow用户

发布于 2017-01-03 11:02:14

异常将抛出在executor线程上,除非捕获或查询异常,否则不可见。例如,您可以写:

代码语言:javascript
复制
Future<?> f = service.submit(new Runnable() { ... }

在main的末尾:

代码语言:javascript
复制
try {
  f.get();
} catch (ExecutionException | InterruptedException e) {
  e.printStackTrace();
}

这将向你展示NPE。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41441861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档