一、原子数组
有些改变的不只是共享变量的引用,而是更改所引用对象的内部数据。
比如共享变量是一个数组,不想改数组的地址,而是想改数组的内部数据,同时保证更改的过程是原子性的,是线程安全的,故引入原子数组。
- AtomicIntegerArray
- AtomicLongArray
- AtomicReferenceArray
如果非原子数组由1000个线程同时更改,会出现线程安全问题
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicMarkableReference;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicStampedReference;
public class Test{
public static void main(String[] args) throws InterruptedException {
ArrayTest arrayTest = new ArrayTest();
for(int i=0;i<10000;i++){
new Thread(()->{
arrayTest.incerementIntegerArray();
}).start();
}
Thread.sleep(2000);//主线程等待两秒后
//打印数组
for (int i=0;i<10;i++){
System.out.println(arrayTest.getIntegerArray()[i]);
}
}
}
class ArrayTest{
private int[] integerArray;//数组
public int[] getIntegerArray() {
return integerArray;
}
public void setIntegerArray(int[] integerArray) {
this.integerArray = integerArray;
}
public ArrayTest(){
this.integerArray =new int[10];//创建一个大小为10的数组
}
public void incerementIntegerArray(){
for(int i=0;i<integerArray.length;i++){
integerArray[i]++;
}
}
}
结果如下:
二、原子更新器
原子更新器又叫做字段更新器,利用字段更新器,可以针对对象的某个域(Field)进行原子操作,当多线程访问同一对象(共享资源)时,保证了对象某一成员变量的线程安全性。只能配合 volatile 修饰的字段使用,否则会出现异常
Exception in thread "main" java.lang.IllegalArgumentException: Must be volatile type
- AtomicReferenceFieldUpdater //域 字段,表示字段是引用类型的
- AtomicIntegerFieldUpdater //表示字段是整型的
- AtomicLongFieldUpdater //表示字段是long型的
import java.util.concurrent.atomic.*;
public class Test{
public static void main(String[] args) {
Student stu = new Student();//创建共享变量Student类对象
/*
* 保护某类的某个属性,设置为原子属性
* 参数分别指定:保护的类、保护的属性、属性的名字
*
* */
AtomicReferenceFieldUpdater updater = AtomicReferenceFieldUpdater.newUpdater(Student.class,String.class,"name");
//接着再拿updater对象操作保护的属性即可,多线程环境下
updater.compareAndSet(stu,null,"张三");
//stu为访问的共享对象,null是期待值,“张三”是修改值
}
}
class Student{
String name;
@Override
public String toString() {
return super.toString();
}
}