原子类的操作
- AtomicInteger
对于普通的变量操作,没有保证原子性。
public class IntegerPractice {
static int a=0;
public static void main(String[] args) {
for(int j=0;j<6;j++)
{
new Thread(() -> {
for (int i = 0; i <10 ; i++) {
a++;
try {
System.out.println(a);
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}
执行结果如下
结果并不按照预期的那样,换成AtomicInteger:
/**
* @author xiaobai
*/
public class IntegerPractice {
public static void main(String[] args) {
AtomicInteger ai=new AtomicInteger(0);
ExecutorService es=new ThreadPoolExecutor(5,20,3, TimeUnit.SECONDS,new LinkedBlockingQueue<>());
for(int i=0;i<6;i++)
{
es.submit(() -> {
for (int j = 0; j < 10; j++) {
ai.incrementAndGet();
System.out.println(ai.get());
}
});
}
}
}
执行结果:
没有出现问题,保证了原子性。
2.更新数组,以AtomicIntegerArray为例:
/**
- @author xiaobai
*/
public class IntegerArrayPractice {
public static void main(String[] args) {
int[] operation={1,2,3,4,5};//初始化数组
AtomicIntegerArray aia=new AtomicIntegerArray(operation);
System.out.println(aia.get(2));//获得数组索引为2的值
System.out.println(aia.incrementAndGet(2));//数组索引为2的值加一
System.out.println(aia.compareAndSet(2,6,4));//数组索引为2的值与6比较,相同就把该值更新为4,否则不更新值
System.out.println(aia.get(2));
System.out.println(aia.addAndGet(2,2));//数组索引为2的值加上2
System.out.println(aia.compareAndSet(2,6,4));
System.out.println(aia.get(2));
}
}
运行结果:
3更新引用数据类型
以AtomicReference为例:
public class ReferencePractice {
public static void main(String[] args) {
String value="atomic reference";
AtomicReference<String> ar=new AtomicReference<>(value);//初始化引用类型对象
System.out.println(ar.get());//获得对象的值
System.out.println(ar.compareAndSet("changed data","success"));//与期望字符串比较,相同就将值更新成"success",否则不更新
ar.set("changed data");
System.out.println(ar.get());
System.out.println(ar.compareAndSet("changed data","success"));
System.out.println(ar.get());
}
}
运行结果:
4.原子更新字段
以AtomicIntegerFieldUpdater为例:
/**
- @author xiaobai
*/
public class IntegerFieldUpdaterPractice {
int a;//a不是要操作的字段,所以可以不用关键词volatile修饰
volatile int b;//b为操作的字段,前面要有volatile
public IntegerFieldUpdaterPractice(int a,int b)
{
this.a=a;
this.b=b;
}
public static void main(String[] args) {
AtomicIntegerFieldUpdater<IntegerFieldUpdaterPractice> aifu=AtomicIntegerFieldUpdater.newUpdater(IntegerFieldUpdaterPractice.class,"b");//声明更新器,操作的类为IntegerFieldUpdaterPractice,操作这个类中的字段b
IntegerFieldUpdaterPractice up=new IntegerFieldUpdaterPractice(2,3);//实例化对象
System.out.println(aifu.get(up));//获得类中指定字段的值
System.out.println( aifu.incrementAndGet(up));//对类中指定字段的值加一
System.out.println(aifu.compareAndSet(up,8,6));//类中指定字段的值与5比较,相同就更新值为6,否则不更新
System.out.println(aifu.get(up));
System.out.println( aifu.addAndGet(up,4));//对类中指定字段的值加4
System.out.println(aifu.compareAndSet(up,8,6));
System.out.println(aifu.get(up));
}
}
运行结果:
note:
- 使用AtomicIntegerFieldUpdater初始得到更新器时需要指明需要操作的类以及类中字段值
- 字段值需要volatile修饰,不修饰的话使用会报java.lang.IllegalArgumentException: Must be volatile type这种异常。
- 变量应该为实例变量,不可以为类变量,即没有static关键词修饰。
5.jdk1.8新增的原子类
有DoubleAccumulator,DoubleAdder,LongAccumulator,LongAdder这四个类,
以LongAdder为例:
public class LongAdderPractice {
public static void main(String[] args) {
LongAdder la=new LongAdder();//LongAdder初始值为0
la.add(5);//对值进行加5
System.out.println(la.sum());
la.increment();
System.out.println(la.sum());
}
}
LongAdder内部有一个Cell类来计数,它的sum=base+各个Cell的和,LongAdder每个线程拥有自己的槽,各个线程一般只对自己槽中的那个值进行CAS操作,每个Cell对象都有一个value值,LongAdder通过Cell数组和base来求出最终的value值。