Java多线程并发锁和原子操作,你真的了解吗?

前言

对于Java多线程,接触最多的莫过于使用synchronized,这个简单易懂,但是这synchronized并非性能最优的。今天我就简单介绍一下几种锁。可能我下面讲的时候其实很多东西不会特别深刻,最好的方式是自己做实验,把各种场景在代码中实验一下,这样发发现很多细节。

volatile

作为Java中的轻量级锁,当多线程中一个线程操作后可以保证其他线程可见,也就是书上所说的“可见性”,另外一个就是“重排序”。所谓重排序指的是JVM对指令的优化。很多人可能在实际实验中发现好像不是如此,最后的例子我也会说明这一点。

synchronized

这个作为Java中“重量级”的线程安全机制被大家所熟知,这个就不在这里做解释了。

java.util.concurrent.locks.ReentrantLock

java.util.concurrent.中是JDK1.5中出的对于一些并发操作的类库,其中包括很多同学很喜欢的原子类,比如说AtomicInteger。它里面原理就是一个CAS,这里就不做过多的阐述,有兴趣的可以看看源码。

好,说一下ReentrantLock,这个锁主要是能显示的添加锁和释放锁,好处是更加灵活,能够更加准确的控制锁,也能确保系统的稳定,比如说“重连”。后面代码会有使用到。

实际场景

上面介绍完了几种锁,下面用具体的代码来看看几种锁的实际用法,以及各种表现形式。代码有点长,这里最好自己实验一下,然后看看结果,并思考这个结果。

输出结果:

i>>>>>381890

vi>>>>>353610

ai>>>>>400000

si>>>>>392718

ri>>>>>392658

从上面的输出结果来看真是让人大感意外:只有原子操作AtomicInteger的结果保证了多线程的安全性,而其他不管是用轻量级的volatile还是重量级的synchronized都没有达到我们想要的效果。这也让我产生了大在的怀疑。难道问题真的这么蹊跷?

从这里不难看出除了AtomicInteger用的是其自己的方法而其他都是用到了Java的语法糖++操作。而这让我想起了++操作并非原子操作,而可能在其中间操作导致了其他线程对其他进行了修改,虽然同样的问题我在《Think in Java》中也找到可以佐证的例子。这里有一个问题就是synchronized:因为我对si已经加了synchronized操作,但是输出的结果令人意外,难道还会有问题?这让我想把这段代码编译成字节码的冲动。好吧,下面看字节码(这里我单独把synchronized这一段操作抽出来,作为分析,其他几个就算了,不然编译后的字节码有点多)

为了方便看,先贴出源代码

下面是字节码,为了节省篇幅,一些不重要的部分我将不贴出

从这里一看从monitorenter进入安全区到monitorexit出安全区没有发现si是处于中间状态的,那又是在哪出的问题呢?这里简单说一下,归根结底仍然是(++)操作非原子操作,可是很多人疑惑了,这里不是加锁了吗?废话不多说,在我的深入探析Java线程锁机制有一个比较详细的分析。

原文发布于微信公众号 - java一日一条(mjx_java)

原文发表时间:2018-07-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏FreeBuf

kill.exe溢出漏洞分析与EXP讨论

* 本文原创作者:zzz66686,本文属FreeBuf原创奖励计划,未经许可禁止转载 1. 前言 前几日,笔者在exploit-db上发现了一个kill.ex...

25190
来自专栏Golang语言社区

Go语言实践:从新手入门到上线真实的小型服务所遇到的那些坑

摘要: Teamwork团队在去年写了近20万行Go代码,建造了一堆速度奇快的小型HTTP服务,本文列出了他们总结的9条经验教训。 为什么选择Go语言?Go...

35570
来自专栏吉浦迅科技

DAY35:阅读流程控制语句

15640
来自专栏阮一峰的网络日志

都柏林核心(Dublin Core)

在上一篇日志中,我介绍了元数据(MetaData),并且说只要有一个集合,就可以定义一套元数据。 这样一来,很自然的,我们就会想到一个问题:有没有可能定义一套通...

28470
来自专栏Golang语言社区

Go语言实践:从新手入门到上线真实的小型服务所遇到的那些坑

摘要: Teamwork团队在去年写了近20万行Go代码,建造了一堆速度奇快的小型HTTP服务,本文列出了他们总结的9条经验教训。 为什么选择Go语言?Go...

35880
来自专栏Java帮帮-微信公众号-技术文章全总结

第一天 Java基础入门【悟空教程】

45270
来自专栏腾讯大讲堂的专栏

设计模式笔记

| 导语 “计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决” “Any problem in computer science can be so...

51380
来自专栏机器学习实践二三事

Numpy使用1

Numpy介绍 NumPy is the fundamental package for scientific computing with Python. I...

21290
来自专栏Golang语言社区

Go语言实战: 编写可维护Go语言代码建议

大家好, 我在接下来的两个会议中的目标是向大家提供有关编写Go代码最佳实践的建议。

23830
来自专栏韩伟的专栏

如何理解模块、组件和对象

模块、组件和对象这三个名词,是软件开发中非常常见的说法。在很多软件平台、库、框架中,都使用这三个名词作为描述其复杂结构的单元结构。模块、组件、对象三者虽然有相似...

26740

扫码关注云+社区

领取腾讯云代金券