原子操作和CAS
前言
(在jvm中创建对象(new对象时)先去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个类的符号是否被加载、解析和初始化过,没有先执行相应的类加载,对象创建jvm中是非常频繁的行为,仅仅是修改一个指针所指向的位置,在并发情况下也并不是线程安全的,可能出现正在给对象A分配内存,指针还没来得及修改,对象B又同时使用原来的指针来分配内存。解决这个问题有两种方案:
一种是对分配内存空间的动作进行同步处理——实际上虚拟机采用CAS(Compare And Swep)配上失败重试的方式保证更新操作的原子性;另一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一块内存,称为本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)。
什么是锁?
锁是synchronized关键字和显示锁,CAS指的由处理系统(cpu)提供的指令,他保证比较和交换的过程中是原子的操作,保证整个操作的原子性,线程安全的,锁是不让其他的线程进入代码块的。
什么是原子操作?如何实现原子操作?
CAS的原理:CAS操作需要输入两个数值,一个旧值(期望操作之前的值)和一个新值,在操作期间先比较旧值有没有发送变化,如果没有发生变化,才交换新值,发生了变化则不交换
CAS(Compare And Swap),指令级别保证这是一个原子操作
三个运算符: 一个内存地址V,一个期望的值A,一个新值B
基本思路:如果地址V上的值和期望的值A相等,就给地址V赋给新值B,如果不是,不做任何操作。
循环(死循环,自旋)里不断的进行CAS操作
CAS的问题:
ABA问题
开销问题
只能保证一个共享变量的原子操作
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class testCAS {
/**
* jdk并发包提供一些类支持原子操作 AtomicInteger AtomicBoolean AtomicLong
* 1.AtomicStampedReference增加版本号,可解决ABA问题
* 2.JVM提供的pause指令 可延迟流水线执行指令,避免内存顺序冲突,可解决循环时间长开销大问题
* 3.AtomicReference类可保证引用对象的原子性,可以把多个变量放在一个对象进行CAS操作,可解决只能保证一个共享变量的原子操作问题
*/
private AtomicInteger atomicI = new AtomicInteger(0);
private int i = 0;
public static void main(String[] args) {
final testCAS cas = new testCAS();
List<Thread> ts = new ArrayList<Thread>(600);
long start = System.currentTimeMillis();
for (int j = 0; j < 100; j++) {
Thread t = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10000; i++) {
cas.count();
cas.safeCount();
}
}
});
ts.add(t);
}
for (Thread t : ts)
t.start();
// 等待所有线程执行完成
for (Thread t : ts) {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("cas.i:" + cas.i);
System.out.println("cas.atomicI.get():" + cas.atomicI.get());
System.out.println("System.currentTimeMillis() - start:" + (System.currentTimeMillis() - start));
}
/**
* 使用CAS实现线程安全的计数器
*/
protected void safeCount() {
for (;;) {
int i = atomicI.get();
boolean suc = atomicI.compareAndSet(i, ++i);
if (suc)
break;
}
}
/**
* 非线程安全计数器
*/
protected void count() {
i++;
}
}
Jdk中相关原子操作类的使用
AtomicMarkableReference,boolean 有没有动过
AtomicStampedReference 动过几次