当Synchronized遇到这玩意儿,有个大坑,要注意! (下)

简介: 当Synchronized遇到这玩意儿,有个大坑,要注意! (下)

image.png

Java Language Architect at Oracle,开发 Java 语言的,就问你怕不怕。

同时,他还是我多次推荐过的《Java并发编程实践》这本书的作者。

好了,现在也找到大佬背书了,接下来带你看看高赞回答是怎么说的。

image.png

前部分就不详说了,其实就是我们前面提到的那一些点,不能用 Integer ,涉及到缓存内、缓存外巴拉巴拉的...

关注划线的部分,我加上自己的理解给你翻译一下:

如果你真的必须用 Integer 作为锁,那么你需要搞一个 Map 或 Integer 的 Set,通过集合类做映射,你就可以保证映射出来的是你想要的明确的一个实例。而这个实例,就那可以拿来做锁。

然后他给出了这样的代码片段:

image.png

就是用 ConcurrentHashMap 然后用 putIfAbsent 方法来做一个映射。

比如多次调用 locks.putIfAbsent(200, 200),在 map 里面也只有一个值为 200 的 Integer 对象,这是 map 的特性保证的,无需过多解释。

但是这个哥们很好,为了防止有人转不过这个弯,他又给大家解释了一下。

首先,他说你也可以这样的写:

image.png

但这样一来,你就会多产生一个很小成本,就是每次访问的时候,如果这个值没有被映射,你都会创建一个 Object 对象。

为了避免这一点,他只是把整数本身保存在 Map 中。这样做的目的是什么?这与直接使用整数本身有什么不同呢?

他是这样解释的,其实就是我前面说的“这是 map 的特性保证的”:

image.png

当你从 Map 中执行 get() 时,会用到 equals() 方法比较键值。

两个相同值的不同 Integer 实例,调用 equals() 方法是会判定为相同的 。

image.png

因此,你可以传递任何数量的 "new Integer(5)" 的不同 Integer 实例作为 getCacheSyncObject 的参数,但是你将永远只能得到传递进来的包含该值的第一个实例。

就是这个意思:

image.png

汇总一句话:就是通过 Map 做了映射,不管你 new 多少个 Integer 出来,这多个 Integer 都会被映射为同一个 Integer,从而保证即使超出 Integer 缓存范围时,也只有一把锁。

除了高赞回答之外,还有两个回答我也想说一下。

第一个是这个:

image.png

image.png

image.png

免费送你一个英语小知识,不用客气。

第二个应该关注的回答排在最后:

image.png

这个哥们叫你看看《Java并发编程实战》的第 5.6 节的内容,里面有你要寻找的答案。

巧了,我手边就有这本书,于是我翻开看了一眼。

第 5.6 节的名称叫做“构建高效且可伸缩的结果缓存”

image.png

好家伙,我仔细一看这一节,发现这是宝贝呀。

你看书里面的示例代码:

image.png

image.png

都是从缓存中获取,拿不到再去构建。

不同的地方在于书上把 synchronize 加在了方法上。但是书上也说了,这是最差的解决方案,只是为了引出问题。

随后他借助了 ConcurrentHashMap、putIfAbsent 和 FutureTask 给出了一个相对较好的解决方案。

你可以看到完全是从另外一个角度去解决问题的,根本就没有在 synchronize 上纠缠,直接第二个方法就拿掉了 synchronize。

看完书上的方案后我才恍然大悟:好家伙,虽然前面给出的方案可以解决这个问题,但是总感觉怪怪的,又说不出来哪里怪。原来是死盯着 synchronize 不放,思路一开始就没打开啊。

书里面一共给出了四段代码,解决方案层层递进,具体是怎么写的,由于书上已经写的很清楚了,我就不赘述了,大家去翻翻书就行了。

没有书的直接在网上搜“构建高效且可伸缩的结果缓存”也能搜出原文。

我就指个路,看去吧。

本文已收录至个人博客,欢迎来玩:

https://www.whywhy.vip/

目录
相关文章
|
5月前
|
监控 安全 IDE
别再瞎用了!synchronized的正确使用姿势在这里!
别再瞎用了!synchronized的正确使用姿势在这里!
213 4
|
7月前
|
安全 Java 程序员
惊呆了!Java多线程里的“synchronized”竟然这么神奇!
【6月更文挑战第20天】Java的`synchronized`关键字是解决线程安全的关键,它确保同一时间只有一个线程访问同步代码。在案例中,`Counter`类的`increment`方法如果不加同步,可能会导致竞态条件。通过使用`synchronized`方法或语句块,可以防止这种情况,确保线程安全。虽然同步会带来性能影响,但它是构建并发应用的重要工具,平衡同步与性能是使用时需考虑的。了解并恰当使用`synchronized`,能有效应对多线程挑战。
23 1
|
8月前
|
Java
面试官:说一说CyclicBarrier的妙用!我:这个没用过...
【5月更文挑战第5天】面试官:说一说CyclicBarrier的妙用!我:这个没用过...
60 2
|
8月前
|
消息中间件 安全 算法
通透!从头到脚讲明白线程锁
线程锁在分布式应用中是重中之重,当谈论线程锁时,通常指的是在多线程编程中使用的同步机制,它可以确保在同一时刻只有一个线程能够访问共享资源,从而避免竞争条件和数据不一致性问题。
330 0
详解JDK锁02:万字文!结合实战案例,手撕AQS源码!
详解JDK锁02:万字文!结合实战案例,手撕AQS源码!
115 0
面试又被问懵了吗?不如把ThreadLocal拆开了揉碎看看
1.为什么用 ThreadLocal? 所谓并发,就是有限资源需要应对远超资源的访问。解决问题的方法,要么增加资源应对访问;要么增加资源的利用率。 所以,相信这年头做开发的多多少少,都会那么几个“线程二三招”、“用锁五六式”。 那所带来的就是多线程访问下的并发安全问题。 共享变量的访问域跨越了原始的单线程,进入了千家万户的线程眼里。谁都可以用,谁都可以改,那不就打起来了吗? 因此,防止并发问题的最好办法,就是不要多线程访问(这科技水平倒退二十年~)。ThreadLocal 顾名思义,将一个变量限制为“线程封闭”:对象只被一个线程持有、访问、修改。
|
设计模式 算法 Java
|
算法 安全 Java
threadlocal再温习
早时总结过《ThreadLocal解析》、《FastThreadLocal解析》 最近看一些资料的时候,又重重发现了这类,不希望再温下,许多知识点,之前已经总结了,这篇文章主要有两个问题: 1、弱引用的意义 2、如何防键冲突
251 0
threadlocal再温习
|
安全
当Synchronized遇到这玩意儿,有个大坑,要注意! (上)
当Synchronized遇到这玩意儿,有个大坑,要注意! (上)
211 0
当Synchronized遇到这玩意儿,有个大坑,要注意! (上)
|
存储 缓存 NoSQL
当Synchronized遇到这玩意儿,有个大坑,要注意! (中)
当Synchronized遇到这玩意儿,有个大坑,要注意! (中)
172 0
当Synchronized遇到这玩意儿,有个大坑,要注意! (中)