volatile无法构建原子的复合操作如i++
优先级反转(高优先级线程无法运行,在等低优先级当前持有的锁)
我们希望:volatile语义,原子更新,但不像锁那么大的开销
cas失败:其他线程修改了内存值
cas看上去代码不少(处理竞争失败的问题,比如重试,放弃等),但实际相对锁的代码路径短(看上去简单,但有很多jvm代码和操作系统代码),即便是无竞争的锁其开销也大于cas,可估算为2倍
原子变量:volatile,AtomicInteger
散列容器(hashmap)的key: 多用不可变对象,且一般重写hashcode和equals(保证equals的对象其hashcode一定相同),若对象可变会导致其hashcode变化其位置不再正确
AtomicInteger 可变,不适用散列容器
AtomicIntegerArray: 每个元素都volatile(putIntVolatile/getIntVolatile)且可实现原子更新
考虑维护两个变量构成的不变性条件
1一把锁锁住两变量,可行, 但是性能差
2 两变量都设为原子变量,不可行,并没有维护不变性条件
3 volatile指向不可变对象(两个变量),若更新使volatile指向新创建的不可变对象,会出现丢失更新(检查再运行,检查时不可变对象为A,准备更为B,实际更新时不可变对象变为C了)
4 AtomicReference指向不可变对象,加入compareAndSet保证原有对象没有改动的情况下更新为新对象
竞争中低:cas明显好于锁 竞争高:cas极易失败,若失败后重试就会进一步加剧竞争,性能差
非阻塞算法:底层的原子机器指令,可伸缩性好,活跃性好,无死锁
考虑用cas实现非阻塞算法
非阻塞栈:栈引用栈顶节点,每个节点单向链接一个节点,push,pop操作修改栈顶节点,可原子引用栈顶节点,compareAndSet(栈顶节点没变的情况下改为新栈顶节点)加循环重试
Node<E> newHead = new Node<E>(item);
Node<E> oldHead;
do {
oldHead = top.get();
newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));
AtomicXXFieldUpdater: 对volatile变量进行cas,原子性稍弱于原子变量(比如compareAndSet在原子变量里
将内存值检测和更新操作合为一个绝对的原子操作,但在updater里不是,若两线程都通过updater去更新,那么
compareAndSet可以认为是原子的,若一线程updater更新,一线程直接修改值,compareAndSet非原子(A线程先比较,B修改,A再修改)
ABA AtomicStampedReference AtomicMarkableReference