问题引出: I++的原子性问题:
public class AtomicTest { public static void main(String[] args) { int i = 0; i = i++; System.out.println(i); } }输出结果为0; 底层操作:
int temp = i; i = i + 1; i = temp;i++步骤:读–>改–>写
public class AtomicTest { public static void main(String[] args) { Atomic at = new Atomic(); for (int i = 0; i < 10; i++) { new Thread(at).start(); } } } class Atomic implements Runnable { private volatile int num = 0; @Override public void run() { try { Thread.sleep(200); } catch (InterruptedException e) { } System.out.println(Thread.currentThread().getName() + ":" + this.getNum()); } public int getNum() { return num++; } public void setNum(int num) { this.num = num; } }结果: Thread-4:0 Thread-3:6 Thread-1:5 Thread-0:4 Thread-6:3 Thread-5:1 Thread-8:1 Thread-2:2 Thread-7:7 Thread-9:8 可以发现是有重复的数字 原子变量:jdk1.5之后juc包下提供了常用的原子变量 1.volatile保证内存可见性 2.CAS(Compare and swap)算法保证数据的原子性,CAS算法是硬件对于并发操作共享数据的支持 CAS包括了三个操作数: 内存值V 预估值A 更新值B 当且仅当V==A时,V=B,否则将不做任何操作。 设置为原子变量:再次运行则无重复问题
private AtomicInteger num = new AtomicInteger(0);简单模拟CAS算法:
public class Simulate { public static void main(String[] args) { CompareAndSwap cs = new CompareAndSwap(); for(int i = 0;i < 10;i ++) { new Thread(new Runnable() { @Override public void run() { int expect = cs.get(); boolean flag = cs.compareAndSet(expect, (int)Math.random() * 100); System.out.println(flag); } }).start(); } } } class CompareAndSwap{ private int value; public synchronized int get() { return value; } public synchronized int compareAndSwap(int expect,int update) { int oldValue = this.get(); if(oldValue == expect) { this.value = update; } return oldValue; } public synchronized boolean compareAndSet(int expect,int update) { return expect == this.compareAndSwap(expect, update); } }CAS算法缺点:只能保证一个变量的原子性,且循环时间有时会过长(失败就继续尝试),ABA问题