2016-07-30 110 views
4

这是从Joshua Bloch编写的一本书中摘取的。如果线程试图获取它已经拥有的锁,会发生什么情况?

我不是英语母语的人,因此有理由要求澄清疑问。

由于内在锁是可重入的,如果一个线程试图 收购它已经持有锁,请求 成功。重入意味着每个线程在 而非**每个调用的基础上获取锁。

通过每个调用的基础,他意味着每个方法调用? 考虑片段:

class Factoriser{ 

     public synchronized void doSomething(){ 
      // code goes here 
     } 
} 

假设有一个线程A,并且能够在具有实例方法doSomething的对象获取锁()。由于某种原因,相同的线程线程A再次获得对同一个对象实例方法doSomething()的锁(想象前一个锁还没有被释放)。

如果我正确理解了Joshua的说法,那么即使有2个方法调用/调用,也只会有一个锁。我的理解是否100%正确。请举例说明。我很困惑,因为提交人在下面的段落中澄清了这一点,这使我更加困惑。

重入是通过将每个锁与一个采集计数和一个拥有线程相关联来实现的。当计数为零时,该锁被认为是不受支持的。当线程获取先前未释放的锁定时,JVM将记录所有者 并将采集计数设置为1。如果同一个线程 再次获取锁定,则计数递增,并且当拥有线程退出同步块时,计数递减 。当计数达到零时,锁定被释放。

如果重入/锁获取不是基于每个调用的基础,那么为什么JVM将对上述场景设置为2来完成计数?

+2

这是一个** ** ** ** ** **。事实上,**有如此多的大胆**,它变得毫无意义**和**分心**。 – Andreas

+0

每个对象只有一个锁。任何数量的调用只需要相同的锁(成功)。当最后一个锁被释放时,该对象不再被锁定。为什么这很难? – markspace

+0

@Andreas:谢谢。删除。 –

回答

2

该计数器用于匹配锁定获取和排泄。该锁可以被释放,只有当计数器为0标记的方法foo()作为​​并调用它的对象上obj等同于以下块:

// calling obj.foo() 
synchronized(obj) { 
    // Do the foo-work 
} 

假设我们有两个同步方法:foo()bar()和后者被称为前者。调用将具有以下结构:

final FooBar obj = new FooBar(); 

// calling obj.foo() 
synchronized(obj) { // 1. here the lock is acquired, the counter is set to 1 

    // do some foo-work 

    // calling obj.bar() 
    synchronized(obj) { // 2. the same lock object, the counter is set to 2 
     // do the bar-work 
    } // 3. the counter is set to 1, the lock is still not released 

    // continue doing the foo-work 
} // 4. the counter is 0, the lock is released 

在不施加反,在步骤3中,我们将释放,因为我们仍然在外部同步块这将是错误的锁定。所以,柜台需要正确实施再入口。

+0

整个对象是否被锁定?或者只有那些标记为该对象同步的方法。 –

+0

我不确定我完全理解你的问题。所有同步方法都使用相同的锁对象 - 调用这些方法的对象(静态同步方法使用'Class'对象)。所以,你可以说整个对象都被锁定了。但是,不标记为已同步的方法仍然可以被调用,而不管活动锁定。只要将每个同步方法想象为一个非同步方法,但如同我在答案中所示,将其置于一个与此方法被调用的对象同步的块上,并且许多事情将更容易理解。 –

+0

重要的是方法本身不会被锁定。它们只能被一个特定的对象(或者一个类,如果它们是静态的)在已经在某个线程中调用并且仍然有效的情况下“锁定”。同时,另一个线程可以在另一个对象上调用相同的方法,并且不会被阻塞,因为它将使用另一个对象进行锁定。所以,它是锁定的对象,而不是方法。但是这些锁仅影响使用同一对象的同步方法和同步块。 –

相关问题