一文搞懂volatile与synchronized区别以及使用

volatile解决内存可见性,禁止指令重排,适用于变量不依赖当前值或无其他变量不变式的场景。synchronized确保内存可见性和原子性,适用于需要锁保护的变量或方法。两者在保证可见性上相同,但synchronized提供更全面的锁定机制,可能造成线程阻塞。
摘要由CSDN通过智能技术生成

一、背景

一提到并发编程,我们便会想到volatile和synchronized这两个关键字,那么首先就要理解关于线程安全的两个名词:内存可见执行顺序

  • 内存可见:线程执行结果在内存中对其他线程的可见性。
  • 执行顺序:控制代码的执行顺序及是否可以并发执行。

二、volatile

volatile解决的是内存可见问题

1.原理

基于CPU内存屏障指令实现的

内存屏障:通俗理解就是一种约定,当遇见它时不对他进行访问

2.volatile修饰的变量可见性

volatile是变量修饰符,其修饰的变量具有内存可见性

一般情况下,Java中为了加快程序的运行效率,会先把主存数据拷贝到线程本地(寄存器或是CPU缓存),操作完成后再把结果从线程本地缓存刷新到主存中,这样就会导致修改后放入变量结果同步到主存中需要一个过程,而此时另外的线程看到的还是修改之前的变量值,这样就会导致不一致

为了解决上述多线程中内存可见的问题,引入了 volatile 关键字,那么它为什么可以解决内存可见性问题呢?

答案: volatile 它会使得所有对 volatile 变量的读写都会直接读写主存,而不是先读写线程本地缓存,这样就保证了变量的内存可见性

3.volatile禁止指令重排

指令重排: 处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证各个语句的执行顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。指令重排序不会影响单个线程的执行,但是会影响到线程并发执行时的正确性

线程执行到volatile修饰变量的读写操作时,其他线程对这个变量的操作肯定已经完成了,且结果已经同步到了主存中,即对其他的线程可见,本线程再对该变量操作完全没有问题的

4.使用范围

volatile关键字仅能实现对原始变量(如boolen、 short 、int 、long等)操作的原子性,不能保证复合操作的原子性,比如 i++

i++,实际上是由三个原子操作组成:read i; inc; write i,假如多个线程同时执行i++,volatile只能保证他们操作的i是同一块内存,但不能保证i结果的正确性,原因如下:

比如有两个线程A和B对volatile修饰的i进行i++操作,i的初始值是0,A线程执行i++时刚读取了i的值0,就切换到B线程了,B线程(从内存中)读取i的值也为0,然后就切换到A线程继续执行i++操作,完成后i就为1了,接着切换到B线程,因为之前已经读取过了,所以继续执行i++操作,最后的结果i就为1了,A和B线程同步到主存中的i的值都是1

5.使用场景

1、对变量的写入操作不依赖变量的当前值,或者只有单个线程更新变量的值

2、该变量没有包含在具有其他变量的不变式中

三、synchronized

synchronized既解决了内存可见性问题,又解决了执行顺序问题

synchronized 可以修饰代码块或方法,既可以保证可见性,又能够保证原子性

原子操作:一系列操作,要么都成功,要么都失败,一个失败则会引起全部都重新再来

1.原理

synchronized 是基于 monitor 实现的

2 synchronized 修饰的代码块或方法保证内存可见性

通过synchronized或者Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存中

3 synchronized 修饰的代码块或方法保证原子性

线程要么不执行(线程没有获取到对象锁),线程要么执行到底(线程获取到了对象锁),直到执行完释放锁

4 synchronized 使用范围

synchronized 不仅能修饰代码块,还可以修饰方法

5 synchronized 使用场景

需要控制多线程访问的方法或者更新的变量

四、volatile 和 synchronized 异同点

1.相同点

volatile 和 synchronized 都保证了内存可见性

2.不同点

1、volatile仅能使用在变量级别,synchronized则可以使用在变量、方法、和类级别的

2、volatile仅能实现变量的修改可见性,不能保证原子性,而synchronized则可以保证变量的修改可见性和原子性

3、volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞

4、volatile标记的变量不会被编译器优化,而synchronized标记的变量可以被编译器优化

5、由于 4 中的区别,在某些情况下 volatile 的性能优于 synchronized

参考博客http://t.csdn.cn/1q7nO

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值