从另一个同步方法调用同步方法是不是安全?

Posted

技术标签:

【中文标题】从另一个同步方法调用同步方法是不是安全?【英文标题】: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 标记为同步,假设它只在上面给出的上下文中调用。 另外,它是否是线程安全的将取决于这两种方法中发生的情况。例如,如果它们调用非线程安全列表,那么它们可能不是线程安全的,如果其他线程可以修改该集合。 作为我猜测的实际问题的答案:是的,同步关键字使用递归锁;您可以安全地从另一个同步方法调用同步方法。 已经有一段时间了,但它仍然是谷歌的第一个热门,所以:是的,同一个对象上的同步块/方法是可重入的。 ***.com/questions/12219376/reentrant-synchronization 【参考方案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

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

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

所以 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 的调用不会同时执行。根据方法的作用,这可能足以说明该类相对于这些方法是线程安全的。

【讨论】:

以上是关于从另一个同步方法调用同步方法是不是安全?的主要内容,如果未能解决你的问题,请参考以下文章

在单元测试中同步调用异步方法是不是不正确?

Java 线程和同步方法未按要求执行

在破坏调用期间从另一个线程未定义的行为调用对象上的方法?

什么是线程安全,实现线程安全都有哪些方法

下个路口见

java的notify方法为啥也要同步