Java多线程原子操作CAS

一,什么是原子操作?如何实现原子操作

1,synchronized可以完成原子操作,他是给予阻塞的锁的机制,但是有问题:

  如果被阻塞的线程优先级很高怎么办?
  拿到锁的线程一直不释放锁怎么办?
  有大量线程进行竞争,消耗cpu。还容易出现死锁
  锁的粒度比较大,影响性能。

二,CAS的原理(Compare And Swap:比较交换)

1,从指令级别保证这是一个原子操作。

每个CAS都包含三个运算符:
  一个内存地址V
  一个期望的值A
  一个新值B

基本思路:
  如果在内存地址V上进行操作,如果说这个地址上存放的值就是我期望的值A。就给地址V赋给新值B.
  如果内存地址上不是我期待的A值,那就什么都不做。
  在循环(这里用的是死循环,不带条件的一直在那里循环。又叫:自旋)里不断的进行CAS操作

利用了现代操作系统都支持CAS的指令,循环这个指令,直到成功为止。
其实是不再语言层面进行处理,而是把它交给了cpu和内存去实现,利用cpu的多处理能力,在硬件层面实现多线程安全。

三,CAS的问题

1,ABA问题

问题描述:
  第一个线程拿到内存地址上的值。此时第二个线程也拿到内存地址上的值,然后修改成B,然后又改回去。
  在第二个线程完成前面一顿操作之后,第一个线程才开始比较内存地址上的是否和A相等。那么比较的结果
  肯定是相同的啦。第二个线程,修改过值,又修改回去。但是对于第二个线程的那些操作,第一个线程却不知道,这是有风险的。

怎么解决:引入版本号,每次变化,版本号都变化。这样每次数据变化都可以感知到

2,开销问题

  在死循环里不断的进行操作,如果这个操作长期不成功,浪费cpu资源

3,只能保证一个共享变量的原子操作

  一个内存地址只能指向一个变量,当有多个共享变量时,就无法保证操作的原子性。
  那么如果有多个共享变量呢?我们可以把多个共享变量变成一个共享变量,比如把多个变量封装到一个类中。

四,JDK中相关原子操作类的使用

1,更新基本类型:

  AtomicBoolean,AtomicInteger,AtomicLong

2,更新数组类:

  AtomicInterArray,AtomicLongArray,AtomicReferenceArray

3,更新引用类型:

  AtomicReference,AtomicMarkableReference,AtomicStampedReference

4,原子更新字段类:

  AtomicReferenceFieldUpdater,AtomicIntegerFieldUpdater,AtomicLongFieldUpdater

------ 本文结束------