目录
为什么需要原子操作类
原子操作,是指一个操作是不可分割,不可中断的;
在java中的运算操作,例如自增或自减,若没有进行额外的同步操作,在多线程环境下操作就是线程不安全的;(n++解析为n=n+1,明显这个操作不具备原子性,多线程并发共享这个变量时必然会出现问题)
如果使用volatile修饰变量呢
volatile特性
- 可见性,保证被修饰的变量在线程间可见,对变量的所有写操作都能立即反应到其他线程中;即volatile修饰的变量在各个线程中是一致的;
只是保证了可见性,在并发情况下并不能保证线程安全(n++不具备原子性)
使用AtomicInteger
incrementAndGet()方法具备原子性
同步,多线程并发访问共享数据时,保证共享数据在同一时刻只被一个线程或一些使用;
阻塞同步和非阻塞同步都是实现线程安全的两个保障手段;非阻塞同步主要解决了阻塞同步中线程阻塞和唤醒带来的性能问题;
非阻塞同步:在并发环境下,某个线程对共享变量先进行操作;如果没有其他线程争用共享数据那操作就成功;如果存在数据争用冲突,就采取补偿措施,比如重试机制,直到成功为止;因为这中乐观的并发策略不需要把线程挂起,也就把这种同步操作称为非阻塞同步;
CAS指令
CAS(compare-and-swap),比较并交换
CAS指令需要3个操作数
- 内存值V,变量的内存地址
- 旧的预期值A
- 新值B
CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则就不执行更新操作;但无论是否更新了V的值,都会返回V的旧值;这个处理过程是一个原子操作;
在JDK1.5后,java程序才可以使用CAS操作,该操作由Unsafe类里面的compareAndSwapInt()和compareAndSwapLong()等几个方法包装提供,编译出的结果就是一条平台相关的处理器CAS指令;
incrementAndGet()方法
-
public final int incrementAndGet() {
-
for (;;) {
-
int current = get();
-
int next = current + 1;
-
if (compareAndSet(current, next))
-
return next;
-
}
-
}
方法在一个无限循环体内,不断尝试将一个比当前值大1的新值赋值给自己;如果失败,说明在执行“获取-设置”操作时已经被其他线程修改过了,于是便再次进入循环执行下一次操作,直到成功为止;