cas是无锁优化,或者叫自旋。通过Atomic类来实现。
由于一些常见的操作,加锁的情况特别多,所以java提供了这些类,内部自带了锁,当然这些锁不是由synchronized来实现的,而是通过cas的操作实现的。
public class study04 {
public static void main(String[] args) {
study04 study =new study04();
List threads =new ArrayList<>();
for (int i=0; i <10; i++){
threads.add(new Thread(study :: m, "thread-"+i));
}
threads.forEach(o -> o.start());
threads.forEach(o -> {
try {
o.join();
}catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println(study.count);
}
AtomicIntegercount =new AtomicInteger(0);
void m(){
for (int i =0; i <10000; i ++){
count.incrementAndGet();
}
}
}
count.incrementAndGet()的内部实现:
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) +1;
}
public final int getAndAddInt(Object var1, long var2, int var4) {
int var5;
do {
var5 =this.getIntVolatile(var1, var2);
}while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
compareAndSwapInt:
cas(V, Expected, NewValue)
if V == Expected
V = NewValue
otherwise try again or fail
V是要修改的值,Expected是期望值,NewValue是新值,如果要修改的值等于期望值,那么代表没有其他线程修改过它,可以设定新值,否则代表有其他线程修改过值,那么cas要重新尝试读取期望值。cas操作是cpu原语级的,中间不允许被打断,是原子性的。
CAS修改的如果是对象会导致ABA问题。线程A发现对象(Expected)的引用还是原来的引用,就允许修改,但其实该对象可能已经被线程B修改过值并重新引用到原来的对象上,线程A无法发现。要解决ABA问题需要引入版本号,compare的时候连版本号一起比较。
CAS是通过Unsafe这个类来实现的。