引用自: https://mp.weixin.qq.com/s/bvqVBnYPdFvpQqdB_4kdUQ
volatile 能使得一个非原子操作变成原子操作吗?
一个典型的例子是在类中有一个long 类型的成员变量。如果你知道该成员变量会被多个线程访问,如计数器、价格等,你最好是将其设置为 volatile。为什么?因为 Java 中读取long 类型变量不是原子的,需要分成两步,如果一个线程正在修改该 long 变量的值,另一个线程可能只能看到该值的一半(前 32 位)。但是对一个 volatile 型的 long 或double 变量的读写是原子。
volatile 类型变量提供什么保证?
volatile 变量提供顺序和可见性保证,例如,JVM或者 JIT为了获得更好的性能会对语句重排序,但是 volatile 类型变量即使在没有同步块的情况下赋值也不会与其他语句重排序。 volatile 提供 happens-before 的保证,确保一个线程的修改能对其他线程是可见的。某些情况下,volatile 还能提供原子性,如读 64 位数据类型,像 long 和 double 都不是原子的,但 volatile 类型的 double 和 long 就是原子的。
volatile 修饰符的有过什么实践?
一种实践是用 volatile 修饰 long 和 double 变量,使其能按原子类型来读写。double 和 long 都是64位宽,因此对这两种类型的读是分为两部分的,第一次读取第一个 32 位,然后再读剩下的 32 位,这个过程不是原子的,但Java 中 volatile 型的 long 或 double 变量的读写是原子的。volatile 修复符的另一个作用是提供内存屏障(memory barrier),例如在分布式框架中的应用。简单的说,就是当你写一个 volatile 变量之前,Java 内存模型会插入一个写屏障(writebarrier),读一个volatile 变量之前,会插入一个读屏障(read barrier)。意思就是说,在你写一个volatile 域时,能保证任何线程都能看到你写的值,同时,在写之前,也能保证任何数值的更新对所有线程是可见的,因为内存屏障会将其他所有写的值更新到缓存。
转载自: https://mp.weixin.qq.com/s/f23I1kyJQoNPu6Ntrx0S6g
读后感:
Java1.6
为Synchronized做了优化,增加了从偏向锁到轻量级锁再到重量级锁的过度,但是在最终转变为重量级锁之后,性能仍然较低. 这其中用到了CAS机制。
CAS优点
- Synchronized属于悲观锁,悲观地认为程序中的并发情况严重,所以严防死守。CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去尝试更新。
- 避免了context switch
CAS缺点
- CPU消耗较大,不适合高并发场景(因为冲突太多,失败率高)。
- ABA问题
- 不能保证代码块的原子性。例如不能保证多个变量同时更新.
乐观锁转悲观锁的经典代码见:ConcurrentHashMap的size方法
1 | public int size() { |
Field的public void setAccessible(boolean flag) 说明
* Set the {@code accessible} flag for this object to * the indicated boolean value. A value of {@code true} indicates that * the reflected object should suppress Java language access * checking when it is used. A value of {@code false} indicates * that the reflected object should enforce Java language access checks.
如果flag设置为true,那么就会压制java语言的访问校验。
1 | public static void main(String[] args) { |
返回值
1 | call method |