您好,欢迎访问一九零五行业门户网

2.原子

在运用cas做lock-free操作中有一个经典的aba问题: 线程1准备用cas将变量的由a替换为b,在此之前,线程2将变量的由a替换为c,又由c替换为a,然后线程1执行cas时发现变量的仍然为a,所以cas成功。但实际上这时的现场已经和最初不同了,尽管cas成功,但可能存
在运用cas做lock-free操作中有一个经典的aba问题:
线程1准备用cas将变量的值由a替换为b,在此之前,线程2将变量的值由a替换为c,又由c替换为a,然后线程1执行cas时发现变量的值仍然为a,所以cas成功。但实际上这时的现场已经和最初不同了,尽管cas成功,但可能存在潜藏的问题,例如下面的例子:
现有一个用单向链表实现的堆栈,栈顶为a,这时线程t1已经知道a.next为b,然后希望用cas将栈顶替换为b:
head.compareandset(a,b);
在t1执行上面这条指令之前,线程t2介入,将a、b出栈,再pushd、c、a,此时堆栈结构如下图,而对象b此时处于游离状态:
此时轮到线程t1执行cas操作,检测发现栈顶仍为a,所以cas成功,栈顶变为b,但实际上b.next为null,所以此时的情况变为:
其中堆栈中只有b一个元素,c和d组成的链表不再存在于堆栈中,平白无故就把c、d丢掉了。
以上就是由于aba问题带来的隐患,各种乐观锁的实现中通常都会用版本戳version来对记录或对象标记,避免并发操作带来的问题,在java中,atomicstampedreference也实现了这个作用,它通过包装[e,integer]的元组来对对象标记版本戳stamp,从而避免aba问题,例如下面的代码分别用atomicinteger和atomicstampedreference来对初始值为100的原子整型变量进行更新,atomicinteger会成功执行cas操作,而加上版本戳的atomicstampedreference对于aba问题会执行cas失败:
public class test { private static atomicinteger atomicint = new atomicinteger(100); private static atomicstampedreference atomicstampedref = new atomicstampedreference( 100, 0); public static void main(string[] args) throws interruptedexception { thread intt1 = new thread(new runnable() { @override public void run() { atomicint.compareandset(100, 101); atomicint.compareandset(101, 100); } }); thread intt2 = new thread(new runnable() { @override public void run() { try { timeunit.seconds.sleep(1); } catch (interruptedexception e) { } boolean c3 = atomicint.compareandset(100, 101); system.out.println(c3); // true } }); intt1.start(); intt2.start(); intt1.join(); intt2.join(); thread reft1 = new thread(new runnable() { @override public void run() { try { timeunit.seconds.sleep(1); } catch (interruptedexception e) { } atomicstampedref.compareandset(100, 101, atomicstampedref.getstamp(), atomicstampedref.getstamp() + 1); atomicstampedref.compareandset(101, 100, atomicstampedref.getstamp(), atomicstampedref.getstamp() + 1); } }); thread reft2 = new thread(new runnable() { @override public void run() { int stamp = atomicstampedref.getstamp(); try { timeunit.seconds.sleep(2); } catch (interruptedexception e) { } boolean c3 = atomicstampedref.compareandset(100, 101, stamp, stamp + 1); system.out.println(c3); // false } }); reft1.start(); reft2.start(); }}
其它类似信息

推荐信息