打赏

java高并发核心要点|系列3|锁的底层实现原理|ABA问题

继续讲CAS算法,上篇文章我们知道,CAS算法底层实现,是通过CPU的原子指令来实现。

那么这里又有一个情景:

话说,有一个线程one从内存位置V中取出A,这时候另一个线程two也从内存中取出A,并且two进行了一些操作变成了B,然后two又将V位置的数据变成A,这时候线程one进行CAS操作发现内存中仍然是A,然后one操作成功。
尽管线程one的CAS操作成功,但是不代表这个过程就是没有问题的。
为什么这样说?我们来想象这样的场景:

在你非常渴的情况下你发现一个盛满水的杯子,你一饮而尽。之后再给杯子里重新倒满水。然后你离开,当杯子的真正主人回来时看到杯子还是盛满水,他当然不知道是否被人喝完重新倒满。这个时候,问题就来了。这杯水已经不是之前的那杯水了。用本山大叔的话来说就是,你大爷还是你大爷,但你大妈已经不是你大妈了!

那么怎么解决这个ABA问题呢?

答案是:版本号。

在这个共享数据区加个版本号,每个线程修改时,都要拿出之前取得的版本号,来进行比较,如果版本号一致,则进行修改,并将版本号+1(当然加多少或减多少都是可以自己定义的)。

实际上,这也是很重要的一个保持数据一致性的设计思想,比如zookeeper,也是用这种机制来保持数据一致性。

为了解决ABA问题,伟大的java为我们提供了AtomicMarkableReference和AtomicStampedReference类。

还是回到上面喝水的例子,如果你是程序员的话,杯子的主人刚好也是你的好基友的话,他会在杯子下放个纸条,上面写上“0”,你喝完水后,把“0”改为“1”,然后你的好基友再回来一看,就知道你已经喝过他的水杯。这时候,他要不要再喝,就很考验你的之间的“基情”了!

下面是演示AtomicStampedReference用法的相关代码:

 

posted @ 2019-06-13 21:19  gyc567  阅读(276)  评论(0编辑  收藏  举报