当前位置: 首页 > 知识库问答 >
问题:

对于Java类,内在锁实际上意味着什么?

强保臣
2023-03-14

为了正确理解Java中并发性的问题和解决方案,我浏览了官方的Java教程。在其中一页中,他们定义了内部锁和同步链接。在这一页,他们说:

只要一个线程拥有一个内在锁,其他线程就不能获得相同的锁。另一个线程在试图获取锁时会阻塞。

此外,他们在同步方法中的锁一节中提到:

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

对我来说,这意味着一旦我从其中一个线程调用同步方法,我将拥有线程的内在锁,因为

内在锁在同步的两个方面都发挥了作用:强制对对象状态的独占访问,以及在对可见性至关重要的关系之前建立。

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

共有3个答案

汤承德
2023-03-14

一个锁一次只能被一个线程持有。这并不违背目的;这就是目的。

线程通过获取一个锁或互斥体来相互排斥,避免在关键部分同时发生动作。这为一系列不同的操作提供了有效的原子性,因此其他线程永远不会看到可能违反一致性保证的中间状态。

阴雪风
2023-03-14

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

这是《Java Concurrency in Practice》一书中的一段摘录:“每个对象都有一个内置锁,这只是一种方便,因此您不必显式创建锁对象”

这本书还说:

对象的内在锁与其状态之间没有内在关系;对象的字段不需要由其内在锁保护,尽管这是许多类使用的完全有效的锁定约定。获取与对象关联的锁并不能阻止其他线程访问该对象。获取锁阻止任何其他线程做的唯一事情是获取相同的锁。每个对象都有内置锁只是一个方便,因此您无需显式创建锁对象。[9]由您来构建锁定协议或同步策略,让您安全地访问共享状态,并在整个程序中一致地使用它们。

但在脚注中它说:

[9]回想起来,这个设计决策可能是一个糟糕的决策:它不仅会令人困惑,而且会迫使JVM实现者在对象大小和锁定性能之间做出权衡。

回答最后一个问题:您不能从另一个线程调用同步方法,但可以从同一个线程继续输入(内部锁是可重入的)。因此,在这种情况下,您必须将锁定想象为序列化来自不同调用线程的方法访问。

如果您不正确地使用锁定,然后您引入了活性危害,那么是的,它是失败的。这就是为什么您必须确保您的并发线程不会太激烈地相互竞争。

正如Brian Goetz在这篇博客文章中所说:

在调优应用程序对同步的使用时,我们应该努力减少实际争用的数量,而不是简单地试图完全避免使用同步

甄文彬
2023-03-14

似乎你有一个没有人指出的误解(不知道它是否导致了错误的结论)。总之,简单回答一下:

内在锁:可以这样想,JVM中的每个对象内部都有一个锁。同步关键字尝试获取目标对象的锁。每当您同步 (a) { doSomething; } 时,实际发生的是

  1. 获取a中的锁
  2. 同步块中的代码正在运行(do的东西
  3. 释放a
  4. 中的锁

我希望你知道

public synchronized void foo() {
  doSomething;
}

在概念上与

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

好了,回到你的问题,最大的问题是:

对我来说,这意味着一旦我从其中一个线程调用同步方法,我将拥有线程的内在锁,因为…

这是错误的。当您调用同步方法时,您无法获得线程的锁。

相反,该线程将拥有“拥有”该方法的对象的固有锁。

例如,在线程1中,您调用a.foo(),并假设foo()是同步的。线程1将获取引用的对象的内在锁。

类似地,如果<code>AClass。bar()被调用(并且bar是同步的和静态方法),将获取AClassClass对象的内部锁。

 类似资料:
  • 问题内容: 我看到的几乎每个Express应用程序都有一个关于中间件的声明,但是我没有找到关于中间件实际上是什么以及该声明在做什么的清晰,简洁的解释。甚至快递文档本身对此也含糊不清。你能帮我解释一下这些概念吗? 问题答案: 中间件 我在一个新项目中将中间件的概念分离了一半。 中间件使您可以定义应执行的操作堆栈。Express服务器本身就是一堆中间件。 然后您可以通过调用将层添加到中间件堆栈 中间件

  • 根据C 11标准(草案n3337)§5/9: -如果两个操作数的类型相同,则无需进一步转换。 -否则,如果两个操作数都具有有符号整数类型或都具有无符号整数类型,则整数转换秩较小的操作数类型应转换为秩较大的操作数类型。 -否则,如果具有无符号整数类型的操作数的秩大于或等于另一个操作数类型的秩,则应将具有有符号整数类型的操作数转换为具有无符号整数类型的操作数的类型。 -否则,如果有符号整数类型的操作数

  • 来自请求率和性能指南-Amazon Simple Storage Service: Amazon S3会自动扩展到高请求率。例如,您的应用程序可以在存储桶中的每个前缀每秒至少实现3,500个PUT/POST/DELETE和5,500个GET请求。存储桶中的前缀数量没有限制。以指数方式提高您的读取或写入性能很简单。例如,如果您在Amazon S3存储桶中创建10个前缀以并行化读取,您可以将读取性能扩

  • 问题内容: 下面是代码片段。 有人可以向我解释@符号在Java中的含义吗? 问题答案: 这是一个注释。 注释是元数据的一种形式。它们提供的程序数据不属于程序本身。注释对其注释的代码的操作没有直接影响。 注释确实会影响工具和库对待程序的方式,进而会影响正在运行的程序的语义。可以从源文件,类文件中读取注释,也可以在运行时从中读取注释。

  • 我想创建一个

  • 我最近看到新的Gmail API宣布吹嘘OAuth 2.0用户身份验证。 我有点担心,因为在我们的企业Google Apps域中,我已经使用XOAUTH2与Gmail集成。(从本质上讲,XOAUTH2 包括对 IMAP 身份验证的 OAuth 2.0 支持)。 我应该担心吗? 新的Gmail API是否意味着XOAUTH2的终结开始?