资讯专栏INFORMATION COLUMN

JAVA多线程机制解析-volatile&synchronized

dendoink / 1949人阅读

摘要:当一个线程持有重量级锁时,另外一个线程就会被直接踢到同步队列中等待。

java代码先编译成字节码,字节码最后编译成cpu指令,因此Java的多线程实现最终依赖于jvm和cpu的实现

synchronized和volatile

我们先来讨论一下volatile关键字的作用以及实现机制,每个线程看到的用volatile修饰的变量的值都是最新的,更深入的解释就涉及到Java的内存模型了,我们知道Java将内存分为主内存和线程私有内存,所有的全局变量都在主内存中,每个线程使用变量时都会从主内存中读取变量,然后放到各自线程的私有内存中,这样线程使用变量时就不用每次都去读取主内存了,当然这也产生了一个问题,如果线程修改了变量值,但是修改的值没有及时地同步到主内存中,那么其他线程看到的变量值仍然是未修改之前的值,这就产生了并发问题,而当这个变量用volatile修饰后,每次线程都会从主内存中读取变量值,也就是说抛弃了线程私有内存中的变量值,而线程每次修改变量后,就会将修改后的值同步到主内存中去。

理论上volatile就是这么实现滴,但是volatile最终会被编译成机器指令,所以volatile这种机制也需要相关的机器指令支持,学习过计算机组成原理的同学们都知道计算机在cpu和主内存直接有一个cache缓存,是不是和Java模型很类似,当然还不一样,其实volatile最终使用了cpu缓存一致性也就是说将缓存中的内容立刻更新到主内存中去,同时将其他缓存中的值置为无效。如果大家有探索精神可以看看看看volatile被编程为的汇编代码,就会发现volatile是用Lock信号实现地。

下面我们再来说说synchronized关键字,学习过Java的同学应该都知道这个关键字是用来实现多线程同步的,synchronized的具体用法这里就不介绍了,我们来聊下这个关键字的具体实现,看过Java并发的同学都会发现synchronized被称为重量级锁,怎么理解这个重量级的概念那?反正我的理解是加锁解锁耗费地时间多,导致并发度比较低呗,但是随着JDK版本的升级,synchronized的性能和并发库中Lock的性能基本持平。好了言归正传,synchronized的具体实现不知道同学们了解多少,我想大部分人应该能说出synchronized由一个同步队列和对象监视器实现,线程进入同步块时,先获取监视器如果成功就进入同步块,如果不成功就进入同步队列等待另外一个线程从同步块退出,没错这就是synchronized的实现,如果你只知道这些说明你了解的还不够深入,因为你还需要知道偏向锁、轻量级锁和synchronized的关系,在这里我就抛砖引玉先说说我自己的理解吧,我们都知道一个Java对象有三部分组成,对象头,实体部分,对齐填充部分,这个对象头就是实现synchronized的关键,在比较老的JDK版本中,一个线程进入同步代码块时就要获取互斥量,不管有没有其他线程,改进后的synchronized,线程一般先获取偏向锁,如果有竞争就膨胀为轻量级锁或者重量级锁,轻量级锁又会膨胀为重量级锁,那么偏向锁、轻量级锁、重量级锁有什么区别那?

偏向锁:

对象头中设置偏向锁标记,同时将当前线程的线程id保存在对象头和栈的锁记录空间中;

轻量级锁

将对象头的内容复制到当前线程栈的锁记录空间中,同时将对象头设置为指向锁记录空间的指针;

重量级锁
将对象头的内容复制到当前线程的锁记录空间中,同时将对象头设置为指向互斥量的指针;

当一个线程进入同步快时,先通过cas设置对象头为偏向锁,若设置成功则说明线程获取锁,若设置不成功,说明锁存在竞争,持有偏向锁的线程就要释放偏向锁,偏向锁膨胀为轻量级锁或重量级锁。
当一个线程持有轻量级锁,另外一个线程尝试获取锁,获取失败,则另外一个线程会自旋等待,若等待一段时间仍未获取锁,则线程进入等待,持有轻量级锁的线程就会在安全点处释放轻量级锁,轻量级锁也会膨胀为重量级锁。
当一个线程持有重量级锁时,另外一个线程就会被直接踢到同步队列中等待。

(安全点是jvm的一些特殊位置,在这个位置上所有的线程都会暂停工作,一般在安全点处进行垃圾回收,还有一个概念是安全区域,安全区域是指在一块代码内引用关系不会发生变化,这个代码的任何位置进行垃圾回收都是可以的)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/71036.html

相关文章

  • Java线程&高并发

    摘要:线程启动规则对象的方法先行发生于此线程的每一个动作。所以局部变量是不被多个线程所共享的,也就不会出现并发问题。通过获取到数据,放入当前线程处理完之后将当前线程中的信息移除。主线程必须在启动其他线程后立即调用方法。 一、线程安全性 定义:当多个线程访问某个类时,不管运行时环境采用何种调度方式,或者这些线程将如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行...

    SQC 评论0 收藏0
  • 深入理解 Java 线程系列(1)——一个简单需求的并行改造 & Java线程的通信问题

    摘要:所以接下来,我们需要简单的介绍下多线程中的并发通信模型。比如中,以及各种锁机制,均为了解决线程间公共状态的串行访问问题。 并发的学习门槛较高,相较单纯的罗列并发编程 API 的枯燥被动学习方式,本系列文章试图用一个简单的栗子,一步步结合并发编程的相关知识分析旧有实现的不足,再实现逻辑进行分析改进,试图展示例子背后的并发工具与实现原理。 本文是本系列的第一篇文章,提出了一个简单的业务场景...

    ruicbAndroid 评论0 收藏0
  • 线程学习笔记(1):volatilesynchronized

    摘要:今天开始整理学习多线程的知识,谈谈最重要的两个关键字和。但是这样一个过程比较慢,在使用多线程的时候就会出现问题。有序性有序性是指多线程执行结果的正确性。这种机制在多线程中会出现问题,因此可以通过来禁止重排。 今天开始整理学习多线程的知识,谈谈最重要的两个关键字:volatile和synchronized。 一、三个特性 1、原子性 所谓原子性操作就是指这些操作是不可中断的,要么执行过程...

    jk_v1 评论0 收藏0
  • BATJ都爱问的线程面试题

    摘要:今天给大家总结一下,面试中出镜率很高的几个多线程面试题,希望对大家学习和面试都能有所帮助。指令重排在单线程环境下不会出先问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。使用可以禁止的指令重排,保证在多线程环境下也能正常运行。 下面最近发的一些并发编程的文章汇总,通过阅读这些文章大家再看大厂面试中的并发编程问题就没有那么头疼了。今天给大家总结一下,面试中出镜率很高的几个多线...

    高胜山 评论0 收藏0
  • Java - 并发 atomic, synchronization and volatile

    摘要:线程的这种交叉操作会导致线程不安全。原子操作是在多线程环境下避免数据不一致必须的手段。如果声明一个域为一些情况就可以确保多线程访问到的变量是最新的。并发要求一个线程对对象进行了操作,对象发生了变化,这种变化应该对其他线程是可见的。 虽是读书笔记,但是如转载请注明出处 http://segmentfault.com/blog/exploring/ .. 拒绝伸手复制党 一个问题: ...

    StonePanda 评论0 收藏0

发表评论

0条评论

dendoink

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<