volatile为什么不保证原子性?
**number++操作对应的字节码:
number++ 被拆分成3个指令
- 执行 GETFIELD 拿到主内存中的原始值
number[ ** ]- 执行 IADD 进行加
1操作- 执行 PUTFIELD 把工作内存中的值写回主内存中 [ 会造成给主内存重复覆盖相同值 ]
当多个线程并发执行 PUTFIELD 指令的时候,会出现写回主内存覆盖问题,故volatile不能保证原子性。
请你使用代码验证volatile不保证原子性?
public class VolatileThread extends Thread{//1.定义volatile 可见性countprivate volatile int count=0;@Overridepublic void run() {for (int i = 0; i < 100; i++) {count++;System.out.println("count =====>"+count);}}}public class DemoTest {public static void main(String[] args) {VolatileThread volatilethread =new VolatileThread();//2.定义100个线程计算count,按道理count被自增至10000for (int i = 0; i < 100; i++) {new Thread(volatilethread).start();//new VolatileThread().start(); 注意二者区别}}}
解决volatile不保证原子性问题
1.方法前加 synchronized 解决 [ 悲观锁 ]
public class VolatileThread extends Thread{private volatile int count=0;Lock lock = new ReentrantLock();@Overridepublic synchronized void run() { //方法上加 synchronizedfor (int i = 0; i < 100; i++) {count++;System.out.println("count =====>"+count);}}}
2.加锁解决
public class VolatileThread extends Thread{private volatile int count=0;Lock lock = new ReentrantLock(); //1.定义 Lock 对象@Overridepublic void run() {lock.lock(); //2.加锁for (int i = 0; i < 100; i++) {count++;System.out.println("count =====>"+count);}lock.unlock(); //3.解锁}}
3.原子类CAS机制解决 [ 乐观锁 ]
public class VolatileThread extends Thread{private AtomicInteger atomicNumber = new AtomicInteger();@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("count =====>"+(atomicNumber.getAndIncrement()+1));}}}
CAS与Synchronized 比较:乐观锁,悲观锁。
CAS和Synchronized都可以保证多线程环境下共享数据的安全性。那么他们两者有什么区别?
Synchronized是从悲观的角度出发(悲观锁)
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。因此Synchronized我们也将其称之为悲观锁。jdk中的ReentrantLock 也是一种悲观锁。性能较差!!
CAS是从乐观的角度出发 (乐观锁)
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据。CAS这种机制我们也可以将其称之为乐观锁。综合性能较好!
