原子性 - CAS 与 Unsafe

本贴最后更新于 1717 天前,其中的信息可能已经东海扬尘

CAS

Compare And Swap(比较并交换),涉及并发算法时常用到的一种技术。 java.util.concurrent.atomic 包下的原子操作类都是基于 CAS 实现的。

现在市面上的处理器基本都支持 CAS,只不过不同的厂家的实现不一样。
CAS 有三个操作数:内存值 V、旧的预期值 A、要修改的值 B,当且仅当预期值 A 和内存值 V 相同时,将内存值修改为 B 并返回 true,否则什么都不做并返回 false

Java 中的 sun.misc.Unsafe 提供了 CAS 机制

Unsafe

Java 无法直接访问底层操作系统,只能通过本地(native)方法来访问。不过尽管如此,JVM 还是开了一个后门,JDK 中有一个类 Unsafe,它提供了硬件级别的原子操作。比如说获取某个属性在内存中的位置,修改对象的字段值。

但是 并没有办法 直接使用它们,JDK API 文档也没有提供任何关于这个类的方法的解释。对于 Unsafe 类的使用是受限制的。

那么我们怎么样来使用呢?

示例代码

import java.lang.reflect.Field;
import sun.misc.Unsafe;


/**
 * 使用CAS方式进行i++
 * @author ldan
 *
 */
public class CounterUnsafe {

	int i = 0;
	
	//Unsafe工具非常强大 ,可以去修改应用类型的值,可以修改对象的属性,可以修改数组  等等
	private static Unsafe unsafe = null;
	
	//代表了要修改的字段  是一个偏移量
	private static long valueOffset;
	
	static{
		//官方不建议直接使用 
		//unsafe = Unsafe.getUnsafe();
		
		//利用反射原理进行使用
		try {
			Field field = Unsafe.class.getDeclaredField("theUnsafe");
			field.setAccessible(true);
			unsafe = (Unsafe) field.get(null);
			
			//指定要修改的字段
			Field iField = CounterUnsafe.class.getDeclaredField("i");
			valueOffset = unsafe.objectFieldOffset(iField);
		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
			e.printStackTrace();
		}
	}
	
	void add(){
		//i++不是原子性的
		//i++;

		//原子性的i++
		while (true){//只有操作成功才return
			if(unsafe.compareAndSwapInt(this, valueOffset, i, i+1))
				return;
		}
	}
	
	
	public static void main(String[] args) {
		
	}
}

CAS 存在的问题

  1. 仅针对单个变量的操作,不能用于多个变量来实现原子操作。
  2. CAS 自旋的实现,可能让所有线程都出于高频运行,争抢 CPU 执行时间的状态。如果操作长时间不成功,会带来很大的 CPU 资源消耗。
  3. ABA 问题。(无法体现出数据的变动)
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3165 引用 • 8206 回帖
  • CAS
    13 引用 • 21 回帖
  • Unsafe
    1 引用 • 1 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • danl
    作者

    i++