原 ABA问题的演示和解决方案
						
							版权声明:本文为博主原创文章,请尊重他人的劳动成果,转载请附上原文出处链接和本声明。
						
						
							本文链接:https://www.91mszl.com/zhangwuji/article/details/1129
						
						
						
ABA问题具体是什么意思,如下图所示。

假设我们主内存的值为100,线程T1和T2在初始状态下,都会拷贝一个副本到自己的工作内存中,即T1和T2都是100,T1执行完需要10秒钟,T2执行完需要2秒钟,假设T2先将100改为了80,然后和主内存进行比较发现没有被改动,于是更改主内存的值为80,然后T2在将80改为了60,T2在由60改为100,T2更改完成后,假设T1此时执行完成了,将自己工作内存的值100和主内存的值100进行比较,发现没有被改过。这种现象就是ABA问题。
ABA问题的代码演示如下:
package com.mszl.thread;
import java.util.concurrent.atomic.AtomicReference;
/**
 * 功能:ABA问题的演示
 * 备注:更多资料请访问 http://www.91mszl.com
 * @author bobo teacher
 */
public class ABADemo {
	
	static AtomicReference<Integer> rf=new AtomicReference<Integer>(100);
	
	public static void main(String[] args) {
		// t1 线程
		Thread t1=new Thread(new Runnable() {
			@Override
			public void run() {
				rf.compareAndSet(100, 108); // 将值由100更改为108
				System.out.println(Thread.currentThread().getName() + " 当前的值为:" + rf.get());
				
				rf.compareAndSet(108, 100); // 将值由108更改为100
				System.out.println(Thread.currentThread().getName() + " 当前的值为:" + rf.get());
			}
		});
		t1.start();
		
		// t2线程
		Thread t2=new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				boolean flag=rf.compareAndSet(100, 888); // t2 将值更改为888
				System.out.println(flag + "\t" + Thread.currentThread().getName() + " 当前的值为:" + rf.get());
			}
		});
		t2.start();
		
	}
	
}ABA问题的解决方案。AtomicStampedReference
代码如下图所示:
package com.mszl.thread;
import java.util.concurrent.atomic.AtomicStampedReference;
/**
 * 功能:ABA问题的解决方案
 * 备注:更多资料请访问 http://www.91mszl.com
 * @author bobo teacher
 */
public class ABADemo1 {
	
	static AtomicStampedReference<Integer> stampRf=new AtomicStampedReference<Integer>(100, 1);
	
	public static void main(String[] args) {
		// t1 线程
		Thread t1=new Thread(new Runnable() {
			@Override
			public void run() {
				int sp=stampRf.getStamp(); // 获取到当前的版本号
				System.out.println(Thread.currentThread().getName() + "\t 第一次版本号" + sp);
				
				try {
					Thread.sleep(1000); // 保证t2线程拿到版本号
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				stampRf.compareAndSet(100, 108, stampRf.getStamp(), stampRf.getStamp()+1); // 将值由100改为108
				System.out.println(Thread.currentThread().getName() + "\t 当前的值" + stampRf.getReference() + "\t 版本号:" + stampRf.getStamp());
				
				stampRf.compareAndSet(108, 100, stampRf.getStamp(), stampRf.getStamp()+1); // 将值由100改为108
				System.out.println(Thread.currentThread().getName() + "\t 当前的值" + stampRf.getReference() + "\t 版本号:" + stampRf.getStamp());
			}
		});
		t1.start();
		
		// t2线程
		Thread t2=new Thread(new Runnable() {
			@Override
			public void run() {
				int sp=stampRf.getStamp(); // 获取到当前的版本号
				try {
					Thread.sleep(3000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				boolean flag=stampRf.compareAndSet(100, 999, sp, sp+1); // 将值由100改为999
				System.out.println(Thread.currentThread().getName() + "\t 是否修改成功:" + flag + "\t 当前最新版本号" + stampRf.getStamp());
			}
		});
		t2.start();
	}
	
}执行结果:
Thread-0	 第一次版本号1
Thread-0	 当前的值108	 版本号:2
Thread-0	 当前的值100	 版本号:3
Thread-1	 是否修改成功:false	 当前最新版本号32019-11-25 15:15:47 阅读(1450)
名师出品,必属精品 https://www.91mszl.com