volatile保证可见性,不保证原子性
- volatile强制线程到共享内存中读取数据,而不从线程工作内存中读取,从而使变量在多个线程中可见
- volatile无法保证原子性,volatile属于轻量级的同步,性能比synchronized强很多(不加锁),但是只 保证线程见的可见性,并不能替代synchronized的同步功能,netty框架中大量使用了volatile
栗子1:volatile不能保证原子性
sum属性加了volatile关键字
1 | public class ThreadDemo14 implements Runnable { |
运行结果:
多次运行可能结果都不一样。因为volatile不能保证原子性,可能线程A把sum改变了,还没来得及设置回主内存,又被其他线程给读取了。
1 | pool-1-thread-1初始sum=0 |
volatile与static区别
- static保证唯一性,不保证一致性,多个实例共享一个静态变量
- volatile保证一致性,不保证唯一性,多个实例有多个volatile变量
Atomic类的原子性
==Actomic类采用了CAS这种非锁机制==
栗子1:使用AtomicInteger等原子类可以保证共享变量的原子性
1 | public class ThreadDemo14 implements Runnable { |
执行结果:
不管运行多少次,结果都是正确的
1 | pool-1-thread-1初始sum=0 |
栗子2: Atomic类不能保证成员方法的原子性
1 | public class ThreadDemo15 implements Runnable { |
执行结果:
1 | 28 |
使用synchronized可以保证方法的原子性。
1 | public synchronized static void add() { |
执行结果:
1 | 10 |
CAS(Compare and swap)
- JDK提供的非阻塞原子操作,通过硬件保证了比较、更新操作的原子性
- JDK的Unsafe类提供了一系列的compareAndSwap*方法来支持CAS操作
解决ABA问题:
- 给变量分配时间戳、版本来解决ABA问题
- JDK中使用java.util.concurrent.atomic.AtomicStampedReference类给每个变量的状态都分配一个时间 戳,避免ABA问题产生。
栗子1:ABA问题
1 | public class CasDemo0 { |
执行结果:
1 | Thread-1 修改之前 : 0 |