volatile为什么不保证原子性?

**
number++操作对应的字节码

number++ 被拆分成3个指令

  1. 执行 GETFIELD 拿到主内存中的原始值 number [ ** ]
  2. 执行 IADD 进行加1操作
  3. 执行 PUTFIELD 把工作内存中的值写回主内存中 [ 会造成给主内存重复覆盖相同值 ]

当多个线程并发执行 PUTFIELD 指令的时候,会出现写回主内存覆盖问题,故volatile不能保证原子性。

请你使用代码验证volatile不保证原子性?

  1. public class VolatileThread extends Thread{
  2. //1.定义volatile 可见性count
  3. private volatile int count=0;
  4. @Override
  5. public void run() {
  6. for (int i = 0; i < 100; i++) {
  7. count++;
  8. System.out.println("count =====>"+count);
  9. }
  10. }
  11. }
  12. public class DemoTest {
  13. public static void main(String[] args) {
  14. VolatileThread volatilethread =new VolatileThread();
  15. //2.定义100个线程计算count,按道理count被自增至10000
  16. for (int i = 0; i < 100; i++) {
  17. new Thread(volatilethread).start();
  18. //new VolatileThread().start(); 注意二者区别
  19. }
  20. }
  21. }

解决volatile不保证原子性问题

1.方法前加 synchronized 解决 [ 悲观锁 ]

  1. public class VolatileThread extends Thread{
  2. private volatile int count=0;
  3. Lock lock = new ReentrantLock();
  4. @Override
  5. public synchronized void run() { //方法上加 synchronized
  6. for (int i = 0; i < 100; i++) {
  7. count++;
  8. System.out.println("count =====>"+count);
  9. }
  10. }
  11. }

2.加锁解决

  1. public class VolatileThread extends Thread{
  2. private volatile int count=0;
  3. Lock lock = new ReentrantLock(); //1.定义 Lock 对象
  4. @Override
  5. public void run() {
  6. lock.lock(); //2.加锁
  7. for (int i = 0; i < 100; i++) {
  8. count++;
  9. System.out.println("count =====>"+count);
  10. }
  11. lock.unlock(); //3.解锁
  12. }
  13. }

3.原子类CAS机制解决 [ 乐观锁 ]

  1. public class VolatileThread extends Thread{
  2. private AtomicInteger atomicNumber = new AtomicInteger();
  3. @Override
  4. public void run() {
  5. for (int i = 0; i < 100; i++) {
  6. System.out.println("count =====>"+(atomicNumber.getAndIncrement()+1));
  7. }
  8. }
  9. }

CAS与Synchronized 比较:乐观锁,悲观锁。

CASSynchronized都可以保证多线程环境下共享数据的安全性。那么他们两者有什么区别?

Synchronized是从悲观的角度出发(悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。因此Synchronized我们也将其称之为悲观锁jdk中的ReentrantLock 也是一种悲观锁。性能较差!!

CAS是从乐观的角度出发 (乐观锁)
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。CAS这种机制我们也可以将其称之为乐观锁。综合性能较好!