2011-04-27 85 views
70

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

void synchronized method1() { 
    method2() 
} 

void synchronized method2() { 
} 
+0

这篇文章有帮助吗,或者你困惑在哪里? http://kalyanchakravarthy.net/?p=413 – 2011-04-27 02:23:18

+0

是的 - 您实际上并不需要将method2标记为synchronized,假定它只在上面给出的上下文中调用。 – debracey 2011-04-27 02:23:52

+3

另外,它是否是线程安全的将取决于两种方法中发生的情况。例如,如果他们调用非线程安全列表,那么如果其他线程可以修改该集合,则它们可能不是线程安全的。 – 2011-04-27 02:24:20

回答

88

是的,当你方法标记为​​,那么你真的这样做:

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

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

当线程调用进入从方法1方法2,那么将确保其持有的锁this,它已经,然后它可以通过。

当线程直接进入method1或method2时,它会阻塞,直到它可以获得锁(this),然后它将进入。

正如詹姆斯布莱克在评论中指出的那样,你必须知道你在方法体内做了什么。

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

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

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

突然,因为你是在你的未来寻找一个ConcurrentModificationException因为method3是不同步的它不是线程安全的,因此可以通过线程A,而线程B在method1工作进行调用。

+0

我试图回答一个几乎与此处提问相同的问题。这是2个可能的答案(其他2个说不会运行),这是正确的? C. \t该代码将运行,但有潜在的死锁情况 D. \t代码将运行良好,因为Java提供了可重入同步,使线程可以多次获取相同的锁-----我猜测它是D,但也许潜在的死锁情况依赖于方法体? – 2015-05-10 01:35:26

+0

@ user3140993这里的代码没有死锁的机会。 'method3'显示不安全的线程操作,但是您关注的是重入同步。 – pickypg 2015-07-28 02:49:48

1

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

  1. 这是不可能的同一对象的同步方法交错两个调用。当一个线程正在执行一个对象的同步方法时,所有其他线程调用同一对象的同步方法块(挂起执行),直到第一个线程完成对象。

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

所以Java将确保如果两个线程都在执行同样的方法,该方法不会consurrently但接二连三执行。

但是你需要知道的活跃度的问题,http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

而且也不管你是锁定uncessarily,原因在您使用这个,它锁定了整个对象的代码,如果你的对象只需要同步访问一个变量,你应该只锁定该变量。

+0

@Stephen Lee - 你不能锁定一个变量。然后你说'synchronized(this.someVar)'你正在查看引用保存在'someVar'中的对象。区别非常重要。 – 2011-04-27 02:43:41

4

是一种用synchronized调用另一个同步方法线程安全的方法。

一般来说,这是不可能说的。它取决于方法的作用,以及同一类和其他类中的其他方法。

但是,我们可以确定,由不同线程创建的同一个对象上的method1和method2调用不会同时执行。根据这些方法的作用,这个可能是就足以说这个类对于这些方法是线程安全的。