CAS
与锁相比,volatile变量是一种更轻量级的同步机制,不会发生上下文的切换,但是volatile不能用于构建原子的复合操作,因此当一个变量依赖旧值时,就不能使用volatile变量。
CAS是一种无锁算法,是一项乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。其原理就是指当两者进行比较时,如果相等,则证明共享数据没有被修改,替换成新值,然后继续往下运行;如果不相等,说明共享数据已经被修改,放弃已经所做的操作,然后重新执行刚才的操作。容易看出 CAS 操作是基于共享数据不会被修改的假设,采用了类似于数据库的 commit-retry 的模式。当同步冲突出现的机会很少时,这种假设能带来较大的性能提升。
CAS是CPU指令级的操作。CAS并不是无阻塞,只是阻塞并非在语言、线程方面,而是在硬件层面.
在轻度到中度争用的情况下,非阻塞算法的性能会超越阻塞算法,因为CAS多数时间下 都在第一次尝试时成功,而发生争用时的开销也不涉及线程挂起和上下文切换,只多了几个循环迭代,没有争用的CAS要比没有争用的锁便宜的多,而争用的CAS比争用的锁获取涉及更短的延迟。在高度争用的情况下(即有多个线程不断争用一个内存位置的时候),基于锁的算法开始提供比非阻塞算法更好的吞吐率,因为当线程阻塞时,它就会停止争用,耐心地等候轮到自己,从而避免了进一步争用。但是,这么高的争用程度并不常见,因为多数时候,线程会把线程本地的计算与争用共享数据的操作分开,从而给其他线程使用共享数据的机会。
Atomic
包里用到了volatile,但只用于读写,核心用的是CAS算法来保证原子性。一个专门为线程安全设计的Java包,包含多个原子操作类。这个包里面提供了一组原子变量类。其基本的特性就是在多线程环境下,当有多个线程同时执行这些类的实例包含的方法时,具有排他性,即当某个线程进入方法,执行其中的指令时,不会被其他线程打断,而别的线程就像自旋锁一样,一直等到该方法执行完成,才由JVM从等待队列中选择一个另一个线程进入,这只是一种逻辑上的理解。实际上是借助硬件的相关指令来实现的,不会阻塞线程(或者说只是在硬件级别上阻塞了)。可以对基本数据、数组中的基本数据、对类中的基本数据进行操作。原子变量类相当于一种泛化的volatile变量,能够支持原子的和有条件的读-改-写操作。