一、原子数组

有些改变的不只是共享变量的引用,而是更改所引用对象的内部数据。
比如共享变量是一个数组,不想改数组的地址,而是想改数组的内部数据,同时保证更改的过程是原子性的,是线程安全的,故引入原子数组。

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray

如果非原子数组由1000个线程同时更改,会出现线程安全问题

  1. import java.util.concurrent.atomic.AtomicIntegerArray;
  2. import java.util.concurrent.atomic.AtomicMarkableReference;
  3. import java.util.concurrent.atomic.AtomicReference;
  4. import java.util.concurrent.atomic.AtomicStampedReference;
  5. public class Test{
  6. public static void main(String[] args) throws InterruptedException {
  7. ArrayTest arrayTest = new ArrayTest();
  8. for(int i=0;i<10000;i++){
  9. new Thread(()->{
  10. arrayTest.incerementIntegerArray();
  11. }).start();
  12. }
  13. Thread.sleep(2000);//主线程等待两秒后
  14. //打印数组
  15. for (int i=0;i<10;i++){
  16. System.out.println(arrayTest.getIntegerArray()[i]);
  17. }
  18. }
  19. }
  20. class ArrayTest{
  21. private int[] integerArray;//数组
  22. public int[] getIntegerArray() {
  23. return integerArray;
  24. }
  25. public void setIntegerArray(int[] integerArray) {
  26. this.integerArray = integerArray;
  27. }
  28. public ArrayTest(){
  29. this.integerArray =new int[10];//创建一个大小为10的数组
  30. }
  31. public void incerementIntegerArray(){
  32. for(int i=0;i<integerArray.length;i++){
  33. integerArray[i]++;
  34. }
  35. }
  36. }

结果如下:

image.png

二、原子更新器

原子更新器又叫做字段更新器,利用字段更新器,可以针对对象的某个域(Field)进行原子操作,当多线程访问同一对象(共享资源)时,保证了对象某一成员变量的线程安全性。只能配合 volatile 修饰的字段使用,否则会出现异常

  1. Exception in thread "main" java.lang.IllegalArgumentException: Must be volatile type
  • AtomicReferenceFieldUpdater //域 字段,表示字段是引用类型的
  • AtomicIntegerFieldUpdater //表示字段是整型的
  • AtomicLongFieldUpdater //表示字段是long型的
  1. import java.util.concurrent.atomic.*;
  2. public class Test{
  3. public static void main(String[] args) {
  4. Student stu = new Student();//创建共享变量Student类对象
  5. /*
  6. * 保护某类的某个属性,设置为原子属性
  7. * 参数分别指定:保护的类、保护的属性、属性的名字
  8. *
  9. * */
  10. AtomicReferenceFieldUpdater updater = AtomicReferenceFieldUpdater.newUpdater(Student.class,String.class,"name");
  11. //接着再拿updater对象操作保护的属性即可,多线程环境下
  12. updater.compareAndSet(stu,null,"张三");
  13. //stu为访问的共享对象,null是期待值,“张三”是修改值
  14. }
  15. }
  16. class Student{
  17. String name;
  18. @Override
  19. public String toString() {
  20. return super.toString();
  21. }
  22. }