从ObjectPool到CAS指令( 二 )

上面代码中,有一个点解释一下Interlocked.CompareExchange(ref _firstItem, null, item) != item,其中!=item,如果其等于item就说明交换成功了,当前线程获取到_firstItem元素的期间没有其它线程修改_firstItem的值 。
Return 方法Retrun(T obj)方法是ObjectPool另外一个重要的方法,它的作用就是当程序代码把从池中获取的对象使用完以后,将其归还到池中 。同样,它也使用CAS指令来解决多线程资源争用的问题,代码如下所示:
public override void Return(T obj){// 使用策略的Return方法对元素进行处理// 比如 List<T> 需要调用Claer方法清除集合内元素// StringBuilder之类的也需要调用Claer方法清除缓存的字符if (_isDefaultPolicy || (_fastPolicy?.Return(obj) ?? _policy.Return(obj))){// 先尝试将归还的元素赋值到 _firstItem中if (_firstItem != null || Interlocked.CompareExchange(ref _firstItem, obj, null) != null){var items = _items;// 如果 _firstItem已经存在元素// 那么遍历整个数组空间 找一个存储为null的空位将对象存储起来for (var i = 0; i < items.Length && Interlocked.CompareExchange(ref items[i].Element, obj, null) != null; ++i){}}}}从核心的Get()Set()方法来看,其实整个代码是比较简单的,除了有一个_firstItem有一个简单的优化,其余没有什么特别的复杂的逻辑 。
主要的关键就在Interlocked.CompareExchange方法上,我们在下文来仔细研究一下这个方法 。
关于 Interlocked.CompareExchangeInterlocked.CompareExchange它实际上是一个CAS的实现,也就是Compare And Swap,从名字就可以看出来,它就是比较然后交换的意思 。
从下面的代码段我们也可以看出来,它总共需要三个参数 。其特性就是只有当localtion1 == comparand的时候才会将value赋值给localtion1,另外吧localtion1的原始值返回出来,这些操作都是原子性的 。
// localtion1 需要比较的引用A// value 计划给引用A 赋的值// comparand 和引用A比较的引用public static T CompareExchange<T> (ref T location1, T value, T comparand)where T : class;一个简单的流程如下所示:

从ObjectPool到CAS指令

文章插图
简单的使用代码如下所示:
【从ObjectPool到CAS指令】var a = 1;// a == 1的话就将其置为0// 判断是否成功就看返回的值是否为a的原始值if(Interlocked.CompareExchange(ref a, 0, 1) == 1) Console.WriteLine("1.成功");// 现在a已经变为0 这个交换不会成功if(Interlocked.CompareExchange(ref a, 0, 1) == 1) Console.WriteLine("2.成功");结果如下所示,只有当a的原始值为1的时候,才会交换成功:
从ObjectPool到CAS指令

文章插图
那么Interlocked.CompareExchange是如何做到原子性的?在多核CPU中,数据可能在内存或者L1、L2、L3中(如下图所示),我们如何保证能原子性的对某个数据进行操作?
从ObjectPool到CAS指令

文章插图
实际上这是CPU提供的功能,如果查看过JIT编译的结果,可以看到CompareExchange是由一条叫lock cmpxchgl的汇编指令支撑的 。
从ObjectPool到CAS指令

文章插图
其中lock是一个指令前缀,汇编指令被lock修饰后会成为"原子的",lock指令有两种实现方法: