【问题标题】:Is it safe to call a synchronized method from another synchronized method?从另一个同步方法调用同步方法是否安全?
【发布时间】:2011-08-13 12:10:57
【问题描述】:

如果一个同步方法调用另一个同步方法,它是线程安全的吗?

void synchronized method1() {
     method2()
}

void synchronized method2() {
}

【问题讨论】:

  • 这篇文章能帮你解答吗,或者你在哪里困惑? kalyanchakravarthy.net/?p=413
  • 是的 - 你实际上不需要将 method2 标记为同步,假设它只在上面给出的上下文中调用。
  • 另外,它是否是线程安全的将取决于这两种方法中发生的情况。例如,如果它们调用非线程安全列表,那么它们可能不是线程安全的,如果其他线程可以修改该集合。
  • 作为我猜测的实际问题的答案:是的,同步关键字使用递归锁;您可以安全地从另一个同步方法调用同步方法。
  • 已经有一段时间了,但它仍然是谷歌的第一个热门,所以:是的,同一个对象上的同步块/方法是可重入的。 stackoverflow.com/questions/12219376/reentrant-synchronization

标签: java thread-safety


【解决方案1】:

是的,当您将方法标记为synchronized 时,您确实是在这样做:

void method1() {
    synchronized (this) {
        method2()
    }
}

void method2() {
    synchronized (this) {
    }
}

当线程调用从method1进入method2时,它将确保它已经持有this的锁,然后它可以通过。

当线程直接进入method1或method2时,会阻塞,直到能拿到锁(this),才会进入。

正如 James Black 在 cmets 中所指出的,您必须清楚自己在方法体内部所做的事情。

private final List<T> data = new ArrayList<T>();

public synchronized void method1() {
    for (T item : data) {
        // ..
    }
}

public void method3() {
    data.clear();
}

突然之间它就不是线程安全的了,因为您在未来会看到 ConcurrentModificationException,因为 method3 是不同步的,因此当线程 B 在 method1 中工作时可能会被线程 A 调用。

【讨论】:

  • 我正在尝试回答一个与此处提出的问题几乎相同的问题。这些是 2 个可能的答案(另外 2 个说它不会运行),哪个是正确的? C. 代码将运行,但存在潜在的死锁情况 D. 代码将运行良好,因为 Java 提供了可重入同步,使线程能够多次获取同一个锁 ----- 我猜是 D,但也许潜在的死锁情况取决于方法体?
  • @user3140993 这里的代码没有死锁的机会。 method3 显示了不安全的线程操作,但您对可重入同步有所了解。
【解决方案2】:

来自 Java 教程网站http://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

  1. 同一对象上的同步方法的两次调用不可能交错。当一个线程正在为一个对象执行同步方法时,所有其他为同一对象调用同步方法的线程都会阻塞(暂停执行),直到第一个线程处理完该对象。

  2. 当同步方法退出时,它会自动与同一对象的任何后续同步方法调用建立起之前的关系。这保证了对象状态的变化对所有线程都是可见的

所以 Java 会确保如果 2 个线程执行同一个方法,这些方法不会同时执行,而是一个接一个地执行。

但您需要注意 Liveness 问题,http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

还有,无论您是否不必要地锁定,因为在您使用 this 的代码中,它会锁定整个对象,如果您的对象只需要同步访问一个变量,您应该锁定该变量。

【讨论】:

  • @Stephen Lee - 您无法锁定变量。然后你说synchronized (this.someVar) 你正在查看其引用保存在someVar 中的对象。区别很重要。
  • 一个不锁定这个的例子。 private final Object mSync; synchronized (this.mSync) {//some code}
【解决方案3】:

一个标有同步的方法调用另一个同步方法线程安全吗。

一般来说,不能说。这取决于方法做什么,以及同一类和其他类上的其他方法做什么。

但是,我们可以确定不同线程对同一对象的方法 1 和方法 2 的调用不会同时执行。根据方法的作用,这可能足以说明该类相对于这些方法是线程安全的。

【讨论】:

    猜你喜欢
    • 2012-03-20
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 2016-08-13
    • 2014-01-29
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多