最近在看《实战Java高并发编程》(好像是叫这个名字,我记不太清,感觉是本不错的书,关于锁、无锁、死锁、以及Java的各种轮子的具体实现,都有很清晰的介绍,也是在这里第一次接触到了CAS操作。

CAS操作,即compareAndSet,传入一个将要修改的值和这个值的被认为的原始值,如果相同,则进行修改操作,这个简单的操作可以在程序中替换掉锁的使用,大大提高了程序的效率,但同时,在多线程的条件下,使用CAS操作编写正确的无锁程序也是十分有挑战的。

书中详细讲解了一例通过使用CAS操作实现一个线程安全的vector,其中有一个point使我印象非常深刻,是在添加元素时,先获取到尾部的指针,尾部指针是添加两个元素后移动一次(具体原因忘了),获取指针后需要先判断他是否是指向真正的尾,而且在获取指针之后,可能会有其他线程对这个指针进行修改,于是出现了以下神奇的判断,if(t != (t=tail)),即,将尾指针赋值给t,如果该表达式为true,则表明在进行!=比较时,有其他线程对t的值进行了修改,那么便可以认为,当前的值是正确的,t是指向vector尾部的,便可以直接使用,否则,则需要判断t是否真正指向尾部。

这一个简单的表达式感觉魅力无穷,也可能是我太弱了哈哈哈,反正我觉得很厉害,示例中的修改操作,全部靠CAS来保证正确性,如果CAS操作失败了,则会一直重试,直至成功,在多线程的条件下,没有锁的资源竞争,效率很高。

 

大部分情况下,有锁还是很方便的,Java8也对读写锁进行了优化,采用乐观读的模式,首次不加锁直接读,然后判断数据是否被修改过,如果是,则采用悲观模式进行加锁读取,提高了效率;同时,对Automatic包的内容也做了些优化,对AtomicInteger,增加了一种优化过的LongAdder,主要是将单个值更改为一种数组模式,在多线程请求时有效降低资源竞争,在获取值时对数组进行求和返回,在高并发下效率比AtomicInteger大约快一倍左右(我没有实际验证。