2016-07-05 114 views
2

为了正确理解Java中的并发问题和解决方案,我正在阅读官方的Java教程。在他们定义的页面之一内部锁和同步link。在这个页面上,他们说:内部锁实际上对Java类意味着什么?

只要一个线程拥有一个内部锁,其他线程就不会获得相同的锁。当其他线程尝试 获取锁时将阻塞。

另外,它们在部分提锁在同步方法在于:

当一个线程调用一个同步方法,它自动获取 用于该方法的对象并释放它时,内部锁方法返回 。即使返回由未捕获的异常导致 ,也会发生锁定释放。

对我来说,这意味着一旦我称之为同步方法从一个线程,我将有螺纹的内部锁的保持,因为

内在锁起到两个方面的作用的同步: 强制对对象的状态进行独占访问并建立 发生在对可见性至关重要的关系之前。

会另一个线程无法调用同一类的另一个同步方法吗?如果是的话,那么同步方法的全部目的就会失败。不是吗?

+0

您的问题不明确。当您询问“我*无法再调用另一种同步方法...”时,“我”是指什么?根据线程构建您的问题。你问是否同一个线程可以从同步方法调用同步方法?也就是说,Java固有锁重入吗?还是你质疑互斥体的效用? – erickson

+0

内在方法意味着您不必创建一个对象来同步您的方法。相比之下,你可以通过调用'synchronized(myLock){...}'来使用外部锁。这是实践中Java并发性的一个摘录:“每个对象都有内置锁的事实只是一种方便,因此您不需要明确创建锁对象” –

+0

我刚刚更新了问题,以便明确提到的含糊问题由@erickson .. – Swapnil

回答

2

所以只是重复我的评论作为一个答案。内部锁定意味着您不必创建一个对象来同步您的方法。相比之下,您可以通过调用synchronized(myLock) {...}来使用外部锁。

这是一本书Java concurrency in practice的摘录:“每个对象都有一个内置的锁时,这只是一个方便,让你不必明确创建锁定对象”

书中还写道:

对象的固有锁定 与其状态之间没有内在联系;一个对象的字段不需要被内部锁 保护,虽然这是一个完全有效的锁定约定,许多类都使用 。获取与对象关联的锁不会阻止其他线程访问该对象, 获取锁的唯一方法是阻止任何其他线程执行操作,即获取相同锁的 。每个对象都有一个内置锁的事实只是一个便利,因此您不需要显式创建锁对象。 [9] 您可以构建锁定协议或同步策略,以便您安全地访问共享状态,并在整个程序中始终如一地使用它们。

但在脚注它说:

[9]回想起来,这样的设计决策可能是一个坏的:不仅 可以说,它是混乱的,但它迫使JVM实现者做出 对象大小和锁定性能之间的折衷。

并回答最后一个问题:您将无法从另一个线程调用synchronized方法,但可以继续从同一个线程进入(内部锁可重入)。所以你必须想象在这种情况下锁定从不同的调用者线程访问序列化方法。

如果你使用不正确的锁定,然后引入生命危险,那么它是失败的。这就是为什么你必须确保你的并发线程不会相互争夺太多。

由于Brian Goetz puts in this blog entry

在调优应用程序的使用同步的,那么,我们应该尽量 努力减少实际争的量,而不是简单地尝试 避免使用在所有

同步
+1

谢谢你的回答。我想我现在更清楚一点。 – Swapnil

+0

@Swapnil不客气。快乐的编码! –

1

是的,由于固有的锁定,您将无法在同一对象上调用其他同步方法。在对象级别,只有一个线程会获得它。

1

​​方法是否属于同一个类并不重要,重要的是如果方法的调用者线程获取锁定或没有获取锁定,那么它将被允许进入临界区域因为锁是reentrant

如果不是的话,那么一个递归调用会导致死锁,

fn(){ 
synchronized(mutex){ // the current thread has already acquired the mutex 
    fn(); 
} 
} 

FN这里惯于僵局因为锁是重入,即(这已经收购可锁的线程只要仍然获得,就要再次输入并出租关键部分)。

+0

sry,但我更新了我的问题,以便更清楚。我的问题是关于调用另一个'synchronized'方法的另一个线程。 – Swapnil

2

似乎你有一个误解(不知道是否导致了错误的结论),没有人指出。无论如何,一个简短的回答:

内部锁:只要认为它,JVM中的每个对象内部都有一个锁。​​关键字尝试获取目标对象的锁定。每当你synchronized (a) { doSomething; },真正发生的

  1. a锁被收购
  2. 码同步块内运行(doSomething
  3. 释放锁a

祝你知道

public synchronized void foo() { 
    doSomething; 
} 

概念一样

public void foo() { 
    synchronized(this) { 
     doSomething; 
    } 
} 

好了,回到你的问题,最大的问题,恕我直言,是:

对我来说,这意味着一旦我称之为同步方法从一线程,我将有线程以来的内部锁的持有...

这是错误。当你调用一个同步方法时,你是而不是得到线程的锁

取而代之的是,线程将自己的对象是“拥有”方法的内部锁。

例如在thread1中,您调用a.foo(),并假定foo()已同步。 thread1将获取对象a的内在锁定。

同样,如果AClass.bar()被调用(并且bar是同步的并且是静态方法),则将获取AClass Class对象的内部锁。

+0

因此,当我从**线程**调用同步方法并获得**对象**的内部锁定时,我是否可以从另一个线程调用另一个同步方法?很抱歉,我的问题中含糊不清。 – Swapnil

+0

尝试在THAT对象上同步的另一个线程(显式同步,调用该对象的同步方法等)需要等待。你需要清楚*它是什么*同步的方法。如果它只是另一个不相关对象的同步方法,当然可以 –

1

我会无法调用同一类的另一个同步方法吗?如果是的话,那么同步方法的全部目的就会失败。不是吗?

号你不能要求对象级锁同一对象的其他​​方法,你不能调用其他方法static sysnchronized对同一类。

但它并没有打破同步的目的。

如果按照第synchronized方法的其它文档页:

使这些方法​​有两个作用:

  1. 首先,它是不可能在同一个synchronized方法两次调用对象交错。当一个线程正在执行一个对象的同步方法时,所有其他线程调用同一对象的同步方法块(挂起执行),直到第一个线程完成对象。其次,当一个同步方法退出时,它会自动建立一个与先前同步对象的任何后续调用同步方法的before-before关系。这保证了对所有线程都可见的对象状态的更改。

如果允许两个​​方法并行运行。你一定会在共享数据上得到内存不一致的错误。

在另一方面,Lock提供了更好的替代​​构造。

相关SE问题:

Synchronization vs Lock

+0

谢谢你的回答和参考。虽然,你的回答足够好,@Captain Fogetti的回答更详细的解释与其他有用资源的链接。所以,我将其标记为正确。再次感谢。 – Swapnil

2

锁只能由一个线程在同一时间举行。这并不能达到目的;即的目的。

线程MUT ually CLUDE从在临界区同时作用彼此通过获取锁,或互斥。这提供了围绕一系列不同操作的有效原子性,以便其他线程永远不会看到可能违反一致性保证的中间状态。

0

锁可以分为两类 - '可重入'和'不可重入'。 在Java'synchronized'中,接口Lock(类ReentrantLock),接口ReadWriteLock(类ReentrantReadWriteLock)的基本实现是可重入的。 重入是指 - 一个线程可以一次又一次地持有锁。