我在工作中修改了一些并发代码,最近还阅读了关于Intrinsic Locks and Synchronization的Java文档.

假设每个对象都有一个内在锁,我为什么要创建一个单独的对象来控制对特定项的访问呢?

我认识到可能存在这样的用例,其中感兴趣的物品不是malloc‘DObject(intvsInteger),因此没有内在锁,但是……假设我们关心的是同步大约static Object个数据,还会有什么损失吗?

例如:

public class main {
    public static void main (String[] args){
        Integer foo = 10;
        
        synchronized(foo){
            foo ++;
        }
    }
}

如果我想从多个线程同步更新foo,为什么不使用我想要修改的对象呢?这是不是表现得更差了?我看到了许多synchronized(this)和单独的实例,在这些实例中,我们可以出于同步的目的创建锁对象:

public class main {
    public static void main (String[] args){
        Integer foo = 10; 
        Object fooLock = new Object();
        
        synchronized(fooLock){
            foo ++;
        }
    }
}

如果我可以使用实际感兴趣的对象,我为什么要创建fooLock个呢?这实际上是不受鼓励的(不是惯用的),还是有实际的理由不这样做?

我正在考虑为static套接字连接对象执行第一种方法(synchronized(foo)),但我担心的是,我还没有看到关于这方面的讨论.我是不是遗漏了什么?

推荐答案

这是一个 comments ,而不是对你的问题的回答.


你的两个例子并不等同.第二个阻止多个线程*同时进入synchronized个块,但第一个允许多个线程同时进入该块.

这是因为,在第一个语句中,synchronized(foo)foo变量在给定时刻恰好引用的Integer个对象,但是foo++语句重新分配foo,以便它引用不同的对象.不同的线程可以同时位于块中,每个线程在不同的对象上同步.

在第二个例子中,fooLockeffectively不变的.它总是指相同的Object实例.由于每个线程都试图在与其他线程相同的对象上进行同步,因此它们将被迫一次一个地遍历该块.


*实际上,您的两个示例都是完整的程序,不会创建任何新线程.在我的 comments 中,我是imagining,如果你的main(...)函数的主体真的在一些其他函数中,而这些函数在一些较大的程序中被许多线程调用,会发生什么.

Java相关问答推荐

我们如何直接使用kerminldap服务票证来通过ldap进行身份验证并形成LDAP上下文

具有默认分支的JUnit代码覆盖率切换声明

BiPredicate和如何使用它

CriteriaQuery with max

为什么如果数组列表中有重复项,我的代码SOMETIMES不返回true?

Kubernetes的Java客户端检索状态.处于终止状态的Pod的阶段';正在运行';

如何使用值中包含与号的查询参数创建一个java.net.URI

按属性值从流中筛选出重复项

使用Jolt将字段转换为列表

将Spring Boot 3.2.0升级到3.2.1后查询执行错误

在Java中将int[]矩阵添加到ArrayList中,但出现错误

我怎样才能让IntelliJ标记toString()的任何实现?

如何在太阳系模拟器中添加月球?

当我在Java中有一个Synchronized块来递增int时,必须声明一个变量Volatile吗?

在不使用instanceof或强制转换的情况下从父类变量调用子类方法

本机方法(JNI)总是编译的吗?

获取401未经授权,即使在标头中设置了浏览器名称和cookie

将Optionals/null安全添加到嵌套的flatMap/流

关于正则表达式的一个特定问题,该问题与固定宽度负向后看有关

找不到 jar 文件系统提供程序try 使用 jdeps 和 jlink 创建收缩 Java 映像来运行 Minecraft