Java JUC之Atomic系列12大类实例讲解和原理分解(四)

2014-11-24 11:42:02 · 作者: · 浏览: 34
public void run() {
while(!ATOMIC_REFERENCE.compareAndSet("abc2", "abc"));
System.out.println("已经改为原始值!");
}
}.start();
}
}
代码中和原来的例子,唯一的区别就是最后增加了一个线程让他将数据修改为原来的值,并一直尝试修改,直到修改成功为止,为什么没有直接用:方法呢getAndSet方法呢,因为我们的目的是要让某个线程先将他修改为abc2后再让他修改回abc,所以需要这样做;
此时我们得到的结果是:
我是线程:41,我获得了锁进行了对象修改!
已经改为原始值!
我是线程:85,我获得了锁进行了对象修改!
当然你的线程编号多半和我不一样,只要征用到就对,可以发现,有两个线程修改了这个字符串,我们是想那一堆将abc改成abc2的线程仅有一个成功,即使其他线程在他们征用时将其修改为abc,也不能再修改。
此时我们通过类来AtomicStampedReference解决这个问题:
实例代码4(AtomicStampedReference解决ABA问题):
[java]
import java.util.concurrent.atomic.AtomicStampedReference;
public class AtomicStampedReferenceTest {
public final static AtomicStampedReference ATOMIC_REFERENCE = new AtomicStampedReference("abc" , 0);
public static void main(String []args) {
for(int i = 0 ; i < 100 ; i++) {
final int num = i;
final int stamp = ATOMIC_REFERENCE.getStamp();
new Thread() {
public void run() {
try {
Thread.sleep(Math.abs((int)(Math.random() * 100)));
} catch (InterruptedException e) {
e.printStackTrace();
}
if(ATOMIC_REFERENCE.compareAndSet("abc" , "abc2" , stamp , stamp + 1)) {
System.out.println("我是线程:" + num + ",我获得了锁进行了对象修改!");
}
}
}.start();
}
new Thread() {
public void run() {
int stamp = ATOMIC_REFERENCE.getStamp();
while(!ATOMIC_REFERENCE.compareAndSet("abc2", "abc" , stamp , stamp + 1));
System.out.println("已经改回为原始值!");
}
}.start();
}
}
此时再运行程序看到的结果就是我们想要的了,发现将abc修改为abc2的线程仅有一个被访问,虽然被修改回了原始值,但是其他线程也不会再将abc改为abc2。
而类:AtomicMarkableReference和AtomicStampedReference功能差不多,有点区别的是:它描述更加简单的是与否的关系,通常ABA问题只有两种状态,而AtomicStampedReference是多种状态,那么为什么还要有AtomicMarkableReference呢,因为它在处理是与否上面更加具有可读性,而AtomicStampedReference过于随意定义状态,并不便于 阅读大量的是和否的关系,它可以被认为是一个计数器或状态列表等信息,java提倡通过类名知道其意义,所以这个类的存在也是必要的,它的定义就是将数据变换为true|false如下:
[java]
public final static AtomicMarkableReference ATOMIC_MARKABLE_REFERENCE = new AtomicMarkableReference("abc" , false);
操作时使用:
[java]
ATOMIC_MARKABLE_REFERENCE.compareAndSet("abc", "abc2", false, true);
好了,reference的三个类的种类都介绍了,我们下面要开始说Atomic的数组用法,因为我们开始说到的都是一些简单变量和基本数据,操作数组呢?如果你来设计会怎么设计,Atomic的数组要求不允许修改长度等,不像集合类那么丰富的操作,不过它可以让你的数组上每个元素的操作绝对安全的,也就是它细化的力度还是到数组上的元素,为你做了二次包装,所以如果你来设计,就是在原有的操作上增加一个下标访问即可,我们来模拟一个Integer类型的数组,即:AtomicIntegerArray
实例代码5(AtomicIntegerArrayTest.java)
[java]
import java.util.concurrent.atomic.AtomicIntegerArray;
public class AtomicIntegerArrayTest {
/**
* 常见的方法列表
* @see AtomicIntegerArray#addAndGet(int, int) 执行加法,第一个参数为数组的下标,第二个参数为增加的数量,返回增加后的结果
* @see AtomicIntegerArray#compareAndSet(int, int, int) 对比修改,参数1:数组下标,参数2:原始值,参数3,修改目标值,修改成功返回true否则false
* @see AtomicIntegerArray#decrementAndGet(int) 参数为数组下标,将数组对应数字减少1,返回减少后的数据
* @see AtomicIntegerArray#incrementAndGet(int) 参数为数组下标,将数组对应数字增加1,返回增加后的数据