前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >volatile和synchronized 实现原理的差别

volatile和synchronized 实现原理的差别

原创
作者头像
矿泉水
发布2018-05-11 11:53:41
1.7K1
发布2018-05-11 11:53:41
举报
文章被收录于专栏:风中追风风中追风风中追风

提到volatile 和 synchronized 的时候不得不提到的一个东西就是JMM(java Memory Model)java内存模型。

因为在并发的过程中 经常要处理一些 可见性 、 原子性 、 有序性的问题。

并发编程中的两个关键问题是: 线程之间是 如何通信的。

这又分两种情况: 1、共享内存 ——— 隐式通信 volatile 2、 消息传递 ——— 显示通信 synchronized / lock

先看看没有 volatile 跟 synchronized来控制 线程的通信会出现什么问题

java内存模型
java内存模型

线程A把X = 0 改成 X = 1 时, 线程2 并不会马上知道。

什么时候要让线程2去解决这个问题,就成了解决线程直接通信的一个关键。

这也就是 可见性问题的所在。

java 提供了 volatile 和 synchronized 关键字 来处理这个可见性的问题,当然 使用lock 也可以,但这里先暂不做讨论。

先说synchronized是怎么做到的,synchronized 先锁住 共享的内存变量,然后线程A修改完之后将值返回到主内存,然后线程B获得锁以后才能获取值,所以通过代码层面的锁可以解决这个线程之间通信的 可见性问题。

但是代码层面,使用锁的话性能就低了,更好的解决办法是 使用volatile 关键字 来修饰这个共享变量。

下面我们来深入的分析 一下volatile 为什么就能做到比synchronized 性能好 还能保持可见性:

1、对于声明了 volatile 的变量,进行写操作的时候, JVM 会向 处理器发送一条 lock 的前缀指令。 2、将这个变量在自己工作内存的值,强制写回主内存。

此时就算线程A将 X 变量的最新值 写回了主存, 但是线程B不去拿,那线程B自己工作内存里的值也还是旧的,那主内存准备通知线程B 去刷新它自己工作内存中的值呢,所以接着看第三步。

3、在多处理器的情况下,保证各个处理器缓存一致性的特点,就会实现缓存一致性协议。 意思就是:每个处理器会 嗅探到 总线上的所传播的数据来检测自己缓存中的值是不是过期了, 当处理器的缓存对应的内存地址被修改以后,它就会将当前的处理器缓存的值设置为失效状态,然后去读那个最新的值。

这就是volatile 的实现原理,代码层面看起来没有加锁,实际上底层还是加了锁的。但是被JVM优化得很快了,它实现锁的开销很小。

再来看看synchronized的实现原理。 先看一段代码:

public class App {

    public static void main(String[] args) {
        test();
    }

    public static synchronized void test(){
    } 
}

将这段代码编译后,打开命令行,进入App.class所在目录 执行 javap -v App.class命令

可以看到App.class的字节码:

App.clas
App.clas

我们把目光放到 第 4 行跟 第 6 行。 这就是synchronized的作用,调用了

monitorenter 跟 monitorexit 的指令, 这是基于JVM 实现的。

我们通过synchronized 声明了锁的范围, 当前的App对象会有一个自己的监视器,该监视器必须获得 当前对象的锁之后 monitorenter 才有资格去 调用 当前的这个线程方法,也就是字节码的第四行。然后锁运行完以后 就运行第六行指令 将锁释放。

ok 上个图估计会更好容易理解一点:

竞争锁的过程
竞争锁的过程

多个请求进来,想要获取同步代码块的锁,必须先获取 monitorenter ,但monitorenter 只有一个,所以 其它线程 B、C、D、E 就都获取不到锁了,没有获取到锁的线程会被放到一个 synchronizedQueue的队列里。

然后获取到monitorenter 的那个线程 在执行完同步代码后,会 monitor.exit 。通知队列里的 B C D E 线程再去竞争锁。

这就是synchronized 的原理啦。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档