话不多说直接demo
package unsynch;
import java.util.concurrent.atomic.AtomicInteger;
/**
* i++ 的原子性问题,i++就是线程不安全的 它实际上是进行读-改-写操作
*
* CAS其实更像是乐观锁,先比较版本号一样在赋值,如果版本号不一样就不赋值
* synchronized 就是一个悲观锁
*
* 原子变量 JDK1.5之后出现了java.util.concurrent.atomic 下面提供了大量的原子性的变量
* 使用volatile修饰保证内存的可见性
* 采用CAS(Compare-And-Swap 字面意思比较和交换)算法,保证数据的原子性
* CAS是硬件对于并发操作的支持,解决多线程并发的问题,原子变量,ConcurrentHashMap都是采用的这个
* CAS算法采用了三个操作数
* 内存值 V
* 预估值 A
* 更新值 B
* 当且仅当 V == A 时候, 才会 V = B, 否则将不做任何操作
* 当失败的时候,不会放弃CPU的资源,他可以再次尝试修改,直到成功为止
*/
public class TestAtomic {
public static void main(String[] args) {
AtomicDemo ad = new AtomicDemo();
for (int i = 0; i < 10; i++) {
new Thread(ad).start();
}
}
}
class AtomicDemo implements Runnable{
// private int i = 0;
private AtomicInteger i = new AtomicInteger();
@Override
public void run() {
try {
Thread.sleep(200);
} catch (Exception e) {
}
System.out.println(Thread.currentThread().getName() + " : " + getI());
}
public int getI() {
// returm i++;
return i.getAndIncrement(); //相当于 i++
// return i.incrementAndGet(); //相当于 ++i
}
public boolean getIn() {
return i.compareAndSet(0, 1); // 这个就是CAS算法 第一个传入预估的值, 第二个传更新的值
}
}
但是CAS会出现一个ABA的问题
假设有500块, 花了500, 会发了两份消息, 第一次cas(扣500,0)第一个消息 0
第二个消息cas(扣500,500) 这是失败
假如在第二个消息中间, 转入500,那么第二次消息cas还是会失败的
aba 加版本号可以解决