java中atomic(原子包)常用类详解

news2024/11/25 22:45:11

目录

一、简介

二、分类

2.1 基本类型原子类

2.1.1 AtomicInteger和AtomicLong介绍

2.1.1.1 AtomicInteger常用的API源码和注释

2.1.1.2 AtomicInteger常用API使用案例

2.1.2 AtomicBoolean介绍

2.1.2.1 AtomicBoolean常用API源码和注释

2.1.2.2 AtomicBoolean常用API使用案例

2.2 数组类型

2.2.1 AtomicIntegerArray和AtomicLongArray介绍

2.2.1.1 AtomicIntegerArray常用的API源码和注释 

2.2.1.2 AtomicIntegerArray常用API使用案例

2.2.2 AtomicReferenceArray介绍

2.2.2.1 AtomicReferenceArray常用API源码和注释

2.2.2.2 AtomicReferenceArray常用API使用案例

2.3 引用类型

2.3.1 AtomicReference介绍

2.3.2.1 AtomicReference常用API源码和注释

2.3.3.1 AtomicReference常用API使用案例

 2.3.2 AtomicMarkableReference和AtomicStampedReference介绍

2.3.2.1 AtomicMarkableReference常用API源码和注释

2.3.2.2 AtomicMarkableReference常用API使用案例

2.4 对象属性修改类型

2.4.1 对象属性修改原理

2.4.2 AtomicIntegerFieldUpdater和AtomicLongFieldUpdater介绍

2.4.4.1 AtomicIntegerFieldUpdater常用API源码和注释

2.4.4.2 AtomicIntegerFieldUpdater常用API使用案例

2.4.3 AtomicReferenceFieldUpdater介绍

2.4.3.1 AtomicReferenceFieldUpdater常用API源码和注释

2.4.3.2 AtomicReferenceFieldUpdater常用API使用案例


一、简介

原子类是指具有原子特征的类,这个特征最大的特点就是“不可中断的一个或者一系列操作”,要么全部成功,要么全部失败。

java的迸发包java.util.concurrent.atomic下面提供了非常丰富的原子类

二、分类

按照操作数据类型分类可以分为四大类,分别是

  • 基本类型
  • 数组类型
  • 引用类型
  • 对象属性修改类型

2.1 基本类型原子类

  • AtomicInteger整形原子类
  • AtomicBoolean:布尔型原子类
  • AtomicLong:长整型原子类

下面的介绍以JDK11为案例进行介绍

2.1.1 AtomicInteger和AtomicLong介绍

  • AtomicInteger整形原子类

AtomicInteger主要用于以原子方式更新Integer数据类型,并且它提供了丰富的API用于一系列的计算

  • AtomicLong长整形原子类 

AtomicLong作用其实和AtomicInteger是一样的,最大的区别就是作用的数据类型不一致。它的常用API其实是和AtomicInteger相似的,不同的是操作的数据结构不一样,一个长整型原子类,一个是整型原子类。

因为AtomicLong和AtomicInteger最大的区别就是数据类型不一致,所以常用APIAtomicLong这里不进行记录。

2.1.1.1 AtomicInteger常用的API源码和注释
/**
 * 获取到当前值
 */    
public final int get() {
        return value;
}

/** 
 * 设定一个值
 */
public final void set(int newValue) {
        value = newValue;
}

/**
 * 最终设定为给定值,但允许之后的其他内存操作重新排序
 * 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
 */
public final void lazySet(int newValue) {
        U.putIntRelease(this, VALUE, newValue);
}

/**
 * 如果当前值等于预期值,则以原子方式将该值设置为给定的更新值,
 * 如果更新成功,则返回true,否则返 false
 */
public final boolean compareAndSet(int expectedValue, int newValue) {
        return U.compareAndSetInt(this, VALUE, expectedValue, newValue);
}

/**
 * 以原子的方式设置为给定值,并返回旧值
 */
public final int getAndSet(int newValue) {
        return U.getAndSetInt(this, VALUE, newValue);
}

/**
 * 以原子方式将当前值加1,并返回旧值,相当于i++
 */
public final int getAndIncrement() {
        return U.getAndAddInt(this, VALUE, 1);
}

/**
 * 以原子方式将当前值减1,并返回旧值,相当于i--
 */
public final int getAndDecrement() {
        return U.getAndAddInt(this, VALUE, -1);
}

/**
 * 以原子方式将给定值加到当前值,并返回旧值
 */
public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
}

/**
 * 以原子的方式将当前值加1,并返回新值,相当于++i
 */
public final int incrementAndGet() {
        return U.getAndAddInt(this, VALUE, 1) + 1;
}

/**
 * 以原子方式将当前值减1,并返回新值,相当于--i
 */
public final int decrementAndGet() {
        return U.getAndAddInt(this, VALUE, -1) - 1;
}
/**
 * 以原子方式将给定值加到当前值,并返回新值
 */
public final int addAndGet(int delta) {
        return U.getAndAddInt(this, VALUE, delta) + delta;
}

/**
 * 使用给定的函数,以原子的方式更新当前值,并返回更新后的值,该函数接受一个当前值
 * 并计算一个新的值
 */
public final int updateAndGet(IntUnaryOperator updateFunction) {
        int prev = get(), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.applyAsInt(prev);
            if (weakCompareAndSetVolatile(prev, next))
                return next;
            haveNext = (prev == (prev = get()));
        }
}


/**
 * 使用给定函数,以原子方式更新当前值,并返回旧值,该函数接受当前值并计算一个新的值
 */
public final int getAndUpdate(IntUnaryOperator updateFunction) {
        int prev = get(), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.applyAsInt(prev);
            if (weakCompareAndSetVolatile(prev, next))
                return prev;
            haveNext = (prev == (prev = get()));
        }
}
/**
 * 使用给定的函数和值以原子方式更新当前值,并返回一个新的值。
 */
public final int getAndAccumulate(int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev = get(), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = accumulatorFunction.applyAsInt(prev, x);
            if (weakCompareAndSetVolatile(prev, next))
                return prev;
            haveNext = (prev == (prev = get()));
        }
}
2.1.1.2 AtomicInteger常用API使用案例

ThreadPolUtils工具类:线程池工具类_java线程池工具类-CSDN博客

 public static void main(String[] args) {
        AtomicInteger integer = new AtomicInteger();
        integer.set(1); // 设置值
        System.out.println(integer.get()); //输出值
        System.out.println("--------------------------------------------------");
//        ThreadPoolUtils.execute(() -> {
//            for (int i = 0; i < 100; i++) {
//                if (i % 10 == 0) {
//                    try {
//                        Thread.sleep(500);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                }
//                System.out.println(integer.get());
//            }
//        });
//        ThreadPoolUtils.execute(() -> {
//            try {
//                Thread.sleep(1000);
//                System.out.println("-----这个时候对integer进行了变更-----");
//                integer.lazySet(222); //如果是set方法,那么还有可能出现获取到1的情况
//                for (int i = 0; i < 10; i++) {
//                    System.out.println(integer.get());
//                }
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        });
        System.out.println("--------------------------------------------------");
        // 预计的值并不是 2 所以不会进行更新
        boolean a = integer.compareAndSet(2, 10); //输出 false 1
        System.out.println(a + " " + integer.get());
        // 预计的值为1 这个时候会进行更新
        boolean b = integer.compareAndSet(1, 10); //输出 true 10
        System.out.println(b + " " + integer.get());
        System.out.println("---------------------------------------------------");
        int c = integer.getAndSet(20); //返回旧值,将值变更为当前值
        System.out.println("返回旧值:" + c + " integer值变更为:" + integer.get()); //输出返回旧值:10 integer值变更为:20
        System.out.println("---------------------------------------------------");
        integer.set(0);
        int aa = integer.getAndIncrement();
        System.out.println("integer++:" + aa); //输出0
        integer.set(0);
        int bb = integer.incrementAndGet();
        System.out.println("++integer:" + bb); // 输出1
        System.out.println("---------------------------------------------------");
        integer.set(1);
        int cc = integer.getAndDecrement();
        System.out.println("integer--:" + cc); //输出1
        integer.set(1);
        int dd = integer.decrementAndGet();
        System.out.println("--integer:" + dd); //输出0
        System.out.println("---------------------------------------------------");
        integer.set(0);
        int ee = integer.getAndAdd(10);
        System.out.println("getAndAdd返回旧值:" + ee); //输出0
        integer.set(0);
        int gg = integer.addAndGet(10);
        System.out.println("addAndGet返回新值:" + gg);// 输出10
        System.out.println("--------------------------------------------------");
        integer.set(0);
        int ab = integer.updateAndGet(i -> i + 10);
        System.out.println("updateAndGet返回更新好的值:" + ab);//输出10
        integer.set(0);
        int ac = integer.getAndUpdate(i -> i + 10);
        System.out.println("getAndUpdate返回旧值:" + ac + " 实际计算好的值:" + integer.get());//输出 0  10
        System.out.println("--------------------------------------------------");
        integer.set(2);
        integer.getAndAccumulate(100, (x, y) -> x * y);
        System.out.println("getAndAccumulate返回新的值:"+integer.get()); //输出200
    }

2.1.2 AtomicBoolean介绍

  • AtomicBoolean:布尔型原子类

AtomicBoolean主要用于以原子方式更新Boolean数据类型

2.1.2.1 AtomicBoolean常用API源码和注释
/**
 * 期望值与当前值一致的时候,执行变更操作,如果变更成功,则返回true,否则返回false
 */
public final boolean compareAndSet(boolean expectedValue, boolean newValue) {
        return VALUE.compareAndSet(this,
                                   (expectedValue ? 1 : 0),
                                   (newValue ? 1 : 0));
    }

/**
 * 获取到当前值
 */
public final boolean get() {
        return value != 0;
    }

/**
 * 设置一个最新的值,该值的更新对其他线程立即可见
 */
public final void set(boolean newValue) {
        value = newValue ? 1 : 0;
    }

/**
 * 最终设定为给定值
 * 设置之后可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
 */
public final void lazySet(boolean newValue) {
        VALUE.setRelease(this, (newValue ? 1 : 0));
    }

/**
 * 设置一个新值,返回一个旧值
 */
public final boolean getAndSet(boolean newValue) {
        return (int)VALUE.getAndSet(this, (newValue ? 1 : 0)) != 0;
    }
2.1.2.2 AtomicBoolean常用API使用案例
public static void main(String[] args) {
        AtomicBoolean atomicBoolean = new AtomicBoolean();
        atomicBoolean.set(true);
        System.out.println(atomicBoolean.get());
        boolean flag = atomicBoolean.compareAndSet(true,false);
        System.out.println("flag:"+flag+" atomicBoolean:"+atomicBoolean.get()); // 变更成功,返回ture,预计值相等,atomicBoolean返回false,设置成功
        atomicBoolean.set(true);
        boolean flag2 = atomicBoolean.getAndSet(false);
        System.out.println("getAndSet设定一个新的值,返回的是旧的值"+flag2);//返回true
 }

2.2 数组类型

  • AtomicIntegerArray:整形数组原子类
  • AtomicLongArray:长整型数组原子类
  • AtomicReferenceArray:引用类型数组原子类

2.2.1 AtomicIntegerArray和AtomicLongArray介绍

  • AtomicIntegerArray:整形数组原子类

AtomicIntegerArray整型数据原子类,主要是原子的方式去操作整型数组,丰富的API还提供了一系列的计算方式

  • AtomicLongArray:长整型数组原子类

AtomicLongArray长整型数组原子类,它和AtomicIntegerArray最大的区别是操作的数据结构数组不一致,AtomicLongArray主要是针对长整型数组

由于AtomicLongArray常用API其实和AtomicIntegerArray极其相似,最大的区别就是数据类型不一致,所以这里就不再对其进行记录,这里不对AtomicLongArray常用API进行记录,如果有问题可以参考AtomicIntegerArray常用API。

2.2.1.1 AtomicIntegerArray常用的API源码和注释 
/**
 * 获取数组元素值,i是元素的下标
 */
public final int get(int i) {
        return (int)AA.getVolatile(array, i);
}

/**
 * 设置数组元素值,i是下标,newValue是对应的值
 */
public final void set(int i, int newValue) {
        AA.setVolatile(array, i, newValue);
}

/**
 * 以原子方式,对下标为i的数组值加delta,并返回一个新值
 */
public final int addAndGet(int i, int delta) {
        return (int)AA.getAndAdd(array, i, delta) + delta;
}

/**
 *  以原子方式,对下标为i的数组值加delta,并返回一个旧值
 */
public final int getAndAdd(int i, int delta) {
        return (int)AA.getAndAdd(array, i, delta);
}

/**
 * 以原子的方式给下标i数组赋值,并返回旧值
 */
public final int getAndSet(int i, int newValue) {
        return (int)AA.getAndSet(array, i, newValue);
}

/**
 * 给数组下标为i的值加1,并返回旧值,相当于数组下标i的值进行a++操作
 */
public final int getAndIncrement(int i) {
        return (int)AA.getAndAdd(array, i, 1);
}

/**
 * 给数组下标为i的值减1,并返回旧值,相当于数组下标i的值进行a--操作
 */
public final int getAndDecrement(int i) {
        return (int)AA.getAndAdd(array, i, -1);
}

/**
 * 给数组下标为i的值加1,并返回新值,相当于数组下标i的值进行++a操作
 */
public final int incrementAndGet(int i) {
        return (int)AA.getAndAdd(array, i, 1) + 1;
}

/**
 * 给数组下标为i的值减1,并返回新值,相当于数组下标i的值进行--a操作
 */
public final int decrementAndGet(int i) {
        return (int)AA.getAndAdd(array, i, -1) - 1;
}


/**
 *数组下标i的值与期望值一致的时候,就对其值进行更新,更新成功返回true,否则返回false
 */
public final boolean compareAndSet(int i, int expectedValue, int newValue) {
        return AA.compareAndSet(array, i, expectedValue, newValue);
}

/**
 * 使用给定函数,以原子方式给数组下标i更新当前值,并返回旧值,该函数接受当前值并计算一个新的值
 */
public final int getAndUpdate(int i, IntUnaryOperator updateFunction) {
        int prev = get(i), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.applyAsInt(prev);
            if (weakCompareAndSetVolatile(i, prev, next))
                return prev;
            haveNext = (prev == (prev = get(i)));
        }
}

/**
 * 使用给定的函数和值以原子方式更新数组下标i的值,并返回一个新的值。
 */
public final int getAndAccumulate(int i, int x,
                                      IntBinaryOperator accumulatorFunction) {
        int prev = get(i), next = 0;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = accumulatorFunction.applyAsInt(prev, x);
            if (weakCompareAndSetVolatile(i, prev, next))
                return prev;
            haveNext = (prev == (prev = get(i)));
        }
}
2.2.1.2 AtomicIntegerArray常用API使用案例
public static void main(String[] args) {
//        int[] a = new int[12];
//        AtomicIntegerArray array = new AtomicIntegerArray(a);
        //两种创建数组的方式都是一样的
        AtomicIntegerArray array = new AtomicIntegerArray(12);
        array.set(1, 10); //给下标1赋值为10
        System.out.println(array.get(0) + " " + array.get(1));// 输出0  10
        int a = array.addAndGet(1, 10);// 下标1的值+10
        System.out.println("addAndGet返回新值:" + a);// 输出20
        int b = array.getAndAdd(1, 10);
        ;// 下标1的值+10
        System.out.println("getAndadd返回旧值:" + b);// 输出20
        int c = array.getAndSet(0, 10); //给下标0赋值为10
        System.out.println("返回旧值:" + c); // 输出 0
        System.out.println("--------------------------------------------------------");
        array.set(0, 10); //给下标0赋值为10
        int d = array.getAndIncrement(0);
        System.out.println("下标0的值++:" + d); //输出10
        System.out.println("--------------------------------------------------------");
        array.set(0, 10); //给下标0赋值为10
        int e = array.incrementAndGet(0);
        System.out.println("++下标0的值:" + e); //输出11
        System.out.println("--------------------------------------------------------");
        array.set(0, 10); //给下标0赋值为10
        int f = array.getAndDecrement(0);
        System.out.println("下标0的值--:" + f); //输出10
        System.out.println("--------------------------------------------------------");
        array.set(0, 10); //给下标0赋值为10
        int g = array.decrementAndGet(0);
        System.out.println("--下标0的值:" + g); //输出9
        System.out.println("--------------------------------------------------------");
        array.set(0, 10); //给下标0赋值为10
        int h = array.getAndUpdate(0, x -> x + 10);
        System.out.println("返回旧值:" + h + " 新值:" + array.get(0)); // 输出10  20
        System.out.println("--------------------------------------------------------");
        array.set(0, 10); //给下标0赋值为10
        array.getAndAccumulate(0, 100, (x, y) -> x * y);
        System.out.println("返回新值:"+array.get(0)); //输出1000
    }

2.2.2 AtomicReferenceArray介绍

AtomicLongArray引用数组原子类,它主要针对的是引用类型的操作。

2.2.2.1 AtomicReferenceArray常用API源码和注释
/**
 *  获取数组元素值,i是元素的下标
 */
public final E get(int i) {
        return (E)AA.getVolatile(array, i);
}

/**
 * 设置数组元素值,i是下标,newValue是对应的值
 */
public final void set(int i, E newValue) {
        AA.setVolatile(array, i, newValue);
}
/**
 * 将位置i处的元素原子设置为给定值,并返回旧值
 */
public final E getAndSet(int i, E newValue) {
        return (E)AA.getAndSet(array, i, newValue);
}

/**
 * 数组下标i的值与期望值一致的时候,就对其值进行更新,更新成功返回true,否则返回false
 */
public final boolean compareAndSet(int i, E expectedValue, E newValue) {
        return AA.compareAndSet(array, i, expectedValue, newValue);
}

/**
 * 使用给定函数,以原子方式给数组下标i更新当前值,并返回旧值,该函数接受当前值并计算一个新的值
 */
public final E getAndUpdate(int i, UnaryOperator<E> updateFunction) {
        E prev = get(i), next = null;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.apply(prev);
            if (weakCompareAndSetVolatile(i, prev, next))
                return prev;
            haveNext = (prev == (prev = get(i)));
        }
}
/**
 * 使用给定的函数和值以原子方式更新数组下标i的值,并返回一个新的值。
 */
public final E updateAndGet(int i, UnaryOperator<E> updateFunction) {
        E prev = get(i), next = null;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.apply(prev);
            if (weakCompareAndSetVolatile(i, prev, next))
                return next;
            haveNext = (prev == (prev = get(i)));
        }
}
2.2.2.2 AtomicReferenceArray常用API使用案例
public static void main(String[] args) {
        User[] users = new User[2];
        AtomicReferenceArray array = new AtomicReferenceArray(users);
        User user = new User();
        user.setAge(10);
        user.setName("小明");
        array.set(1,user);
        System.out.println(array.get(1).toString());
        User user1 = (User) array.getAndSet(0,user); //返回旧值,给下标0赋值新值
        System.out.println("user1返回旧值:"+user1+" 新值:"+array.get(0)); //旧值输出为null 新值输出user对象值
        System.out.println("---------------------------------------------------------------");
        User user2 = new User();
        user2.setAge(20);
        user2.setName("小明");
        boolean flag = array.compareAndSet(0,user,user2);//如果当前值与期望值一致,返回true,并更新对应下标值
        System.out.println("flag:"+flag+" 新值:"+array.get(0) );//当前值与期望值一致,返回true,并且更新下标为0的数据
        System.out.println("---------------------------------------------------------------");
        User user3 = (User) array.getAndUpdate(0,x-> {
            User user4 = new User();
            user4.setName("小明");
            user4.setAge(30);
            return user4;
        });
        System.out.println("返回的旧值:"+user3+" 新值:"+array.get(0)); //旧值user3的age为20 新值age为30
        System.out.println("---------------------------------------------------------------");
        User user5 = (User) array.updateAndGet(0,x-> {
            User user4 = new User();
            user4.setName("小明");
            user4.setAge(40);
            return user4;
        });
        System.out.println("返回的新值:"+user5); //旧值user5的age为40
    }
}
class User{
    private String name;
    private Integer age;
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

2.3 引用类型

  • AtomicReference:引用类型原子类
  • AtomicMarkableReference:原子更新带有标记的引用类型,通过boolean类型判判断数据是否更改过
  • AtomicStampedReference:原子更新带有版本号的引用类型。

2.3.1 AtomicReference介绍

  • AtomicReference:引用类型原子类

AtomicReference引用类型原子类,主要是对引用类型进行原子性的操作

2.3.2.1 AtomicReference常用API源码和注释
/**
 * 获取对象值值
 */
public final V get() {
        return value;
    }

/**
 * 设置对象值
 */
public final void set(V newValue) {
        value = newValue;
    }

/**
 * 设置新的引用对象值,并返回旧值
 */
public final V getAndSet(V newValue) {
        return (V)VALUE.getAndSet(this, newValue);
    }

/**
 * 如果引用的对象跟期望值一致,那么就对其进行更新,并返回ture,否则返回false
 */
public final boolean compareAndSet(V expectedValue, V newValue) {
        return VALUE.compareAndSet(this, expectedValue, newValue);
    }

/**
 * 给定一个函数,以原子的方式更新当前引用对象值,并返回旧值
 */
public final V getAndUpdate(UnaryOperator<V> updateFunction) {
        V prev = get(), next = null;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.apply(prev);
            if (weakCompareAndSetVolatile(prev, next))
                return prev;
            haveNext = (prev == (prev = get()));
        }
    }

/**
 * 给定一个函数,以原子的方式更新当前引用对象值,并返回新值
 */
public final V updateAndGet(UnaryOperator<V> updateFunction) {
        V prev = get(), next = null;
        for (boolean haveNext = false;;) {
            if (!haveNext)
                next = updateFunction.apply(prev);
            if (weakCompareAndSetVolatile(prev, next))
                return next;
            haveNext = (prev == (prev = get()));
        }
    }
2.3.3.1 AtomicReference常用API使用案例
public class Test {
    public static void main(String[] args) {
        User user = new User();
        user.setName("java");
        user.setAge(19);
        AtomicReference reference = new AtomicReference();
        reference.set(user);
        System.out.println("获取引用对象值" + reference.get().toString()); //输出 获取引用对象值User{name='java', age=19}
        System.out.println("--------------------------------------------");
        User user1 = new User();
        user1.setName("中国");
        user1.setAge(5000);
        User user2 = (User) reference.getAndSet(user1);
        System.out.println("返回旧值:" + user2.toString() + " 获取新值:" + reference.get().toString()); // 输出 返回旧值:User{name='java', age=19} 获取新值:User{name='中国', age=5000}
        System.out.println("--------------------------------------------");
        boolean flag = reference.compareAndSet(user1, user);//预计值一致,返回true,并更新
        System.out.println("预计值一致:" + flag + " 更新以后的值:" + reference.get().toString());
        System.out.println("--------------------------------------------"); // 输出 预计值一致:true 更新以后的值:User{name='java', age=19}
        User user3 = (User) reference.getAndUpdate(x -> {
            User user4 = new User();
            user4.setAge(200);
            user4.setName("美国");
            return user4;
        });
        System.out.println("返回旧值:"+user3.toString()+" 新值:"+reference.get().toString()); //输出 返回旧值:User{name='java', age=19} 新值:User{name='美国', age=200}
        System.out.println("--------------------------------------------");
        User user5 = (User) reference.updateAndGet(x -> {
            User user6 = new User();
            user6.setAge(500);
            user6.setName("英国");
            return user6;
        });
        System.out.println("返回新值:"+user5.toString()+" 更新的值:"+reference.get().toString());// 输出返回新值:User{name='英国', age=500} 更新的值:User{name='英国', age=500}

    }
}

class User {
    private String name;
    private Integer age;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

 2.3.2 AtomicMarkableReference和AtomicStampedReference介绍

  • AtomicMarkableReference:原子更新带有标记的引用类型

AtomicMarkableReference它也是主要对引用类型进行原子性的操作,但它是带有原子更新标记的引用类型,因为他有一个boolean标记,我们可以通过它来判断这个引用类型是否已经更改过

  •  AtomicStampedReference:原子更新带有版本号的引用类型

AtomicStampedReference原子更新带有版本号的引用类型。它和AtomicMarkableReference两者都为了解决ABA的问题。最大的区别在AtomicMarkableReference使用整数来判断数据是否已经更改过了,并且会记录更改过几次。AtomicMarkableReference是通过boolean类型进行判断,数据是否已经更改过了。

由于AtomicStampedReference常用的API和AtomicMarkableReference比较相似,不同的是标记类型不一样,所以这里就不再进行记录,如果有问题,可以参考AtomicMarkableReference的API使用方式i

2.3.2.1 AtomicMarkableReference常用API源码和注释
/**
 * 构造函数
 */
public AtomicMarkableReference(V initialRef, boolean initialMark) {
        pair = Pair.of(initialRef, initialMark);
    }

/**
 * 以原子方式获取当前引用值
 */
public V getReference() {
        return pair.reference;
    }

/**
 * 以原子的方式获取当前标记值
 */
public boolean isMarked() {
        return pair.mark;
    }

/**
 * 以原子方式获取当前引用值和标记值
 */
public V get(boolean[] markHolder) {
        Pair<V> pair = this.pair;
        markHolder[0] = pair.mark;
        return pair.reference;
    }


/**
 * 以原子方式同时更新引用值和标记值,当期望引用值不等于当前引用值时,操作失败,返回false
 * 当期望标记值不等于当前标记值时,操作失败,返回false,当新的引用值和标记值同时相等,不更新,直 
 * 接返回ture,当新的引用值和标记值不同时等于当前值,同时设置新的引用值和标记值,返回true
 */
 public boolean compareAndSet(V       expectedReference,
                                 V       newReference,
                                 boolean expectedMark,
                                 boolean newMark) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedMark == current.mark &&
            ((newReference == current.reference &&
              newMark == current.mark) ||
             casPair(current, Pair.of(newReference, newMark)));
    }

/**
 * 以原子方式,设置当前引用值为新值
 */
public void set(V newReference, boolean newMark) {
        Pair<V> current = pair;
        if (newReference != current.reference || newMark != current.mark)
            this.pair = Pair.of(newReference, newMark);
}

/**
 * 如果引用值保持不变,以原子的方式将标记值设置为新的值,当期望值与引用值不相同的时候,返回false
 * 当操作值与期望值相同的时候,返回true
 */
public boolean attemptMark(V expectedReference, boolean newMark) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            (newMark == current.mark ||
             casPair(current, Pair.of(expectedReference, newMark)));
}
2.3.2.2 AtomicMarkableReference常用API使用案例
public class Test {
    public static void main(String[] args) {
        User user = new User();
        user.setName("java");
        user.setAge(19);
        AtomicMarkableReference reference = new AtomicMarkableReference(user, true);
        System.out.println("获取当前引用值:" + reference.getReference().toString());// 输出 获取当前引用值:User{name='java', age=19}
        System.out.println("获取到当前标记:" + reference.isMarked());// 输出获取到当前标记:true
        System.out.println("--------------------------------------------------------------------");
        User user1 = new User();
        user1.setName("中国");
        user1.setAge(5000);
        reference.set(user1, false); //以原子方式设置新值
        boolean[] flag = {false};
        System.out.println("以原子方式获取当前引用标记值" + reference.get(flag)); // 输出以原子方式获取当前引用标记值User{name='中国', age=5000}
        System.out.println("--------------------------------------------------------------------");
        User user2 = new User();
        user2.setName("美国");
        user2.setAge(200);
        // 如果期望值于当前引用值一致,那么就会修改预计值,并且修改标记
        // 这里期望值是user,跟我们上面设置的值是一致,所以会修改,
        // 因为上面的标记是false,跟我们预计的标记也是一致,所以会修改(标记值和预计值一致,返回true)
        System.out.println("当前标记:"+reference.isMarked());
        boolean flag2 = reference.compareAndSet(user1, user2, false, true);
        System.out.println("是否修改:" + flag2 + " 当前值:" + reference.get(flag)); //输出 是否修改:true 当前值:User{name='美国', age=200}
        System.out.println("--------------------------------------------------------------------");
        //引用值保持不变,变更标记
        System.out.println("当前标记:"+reference.isMarked()); //true
        boolean flag3 = reference.attemptMark(user2 ,false);
        System.out.println(flag3+" 变更以后得标记:"+reference.isMarked());//变更成功 输出 true 变更以后得标记:false

    }
}

class User {
    private String name;
    private Integer age;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

2.4 对象属性修改类型

  • AtomicIntegerFieldUpdater:原子更新整形字段的更新器
  • AtomicLongFieldUpdater:原子更新长整形字段的更新器
  • AtomicReferenceFieldUpdater:原子更新引用类型的字段

2.4.1 对象属性修改原理

他们通过基于反射的API实现细粒度的并发控制,主要的作用是用来更新对象的volatile字段

2.4.2 AtomicIntegerFieldUpdater和AtomicLongFieldUpdater介绍

  • AtomicIntegerFieldUpdater:原子更新整形字段的更新器

AtomicIntegerFieldUpdater主要是对volatile修饰的Integer类型字段进行原子性的一系列操作

  •  AtomicLongFieldUpdater:原子更新长整形字段的更新器

 AtomicLongFieldUpdater主要是对volatile修饰的Long类型字段进行原子性的一系列操作

由于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater常用API都差不多,唯一有区别的是数据类型不一样。AtomicIntegerFieldUpdater主要作用的是volatile修饰的Integer类型字段,AtomicLongFieldUpdater主要作用的是volatile修饰的Long类型字段。所以这里就以AtomicIntegerFieldUpdater为例进行记录

2.4.4.1 AtomicIntegerFieldUpdater常用API源码和注释
/**
 * 用于创建一个新的AtomicIntegerFieldUpdater,它能够以原子方式更新给定类的指定名称的volatile字段
 */
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass,
                                                              String fieldName) {
        return new AtomicIntegerFieldUpdaterImpl<U>
            (tclass, fieldName, Reflection.getCallerClass());
    }

/**
 * 获取指定对象的volatile字段的当前值
 */
 public abstract int get(T obj);


/**
 * 以原子方式设置指定对象的volatile字段的值为新值
 */
public abstract void set(T obj, int newValue);

/**
 * 如果当前指定对象的volatile字段的值与期望值一致,那么就进行原子性更新,并返回true,否则返回 
 * false
 */
public abstract boolean compareAndSet(T obj, int expect, int update);

/**
 * 以原子方式设置指定对象的volatile字段值为新值,并返回该字段的旧值
 *
 */
public int getAndSet(T obj, int newValue) {
        int prev;
        do {
            prev = get(obj);
        } while (!compareAndSet(obj, prev, newValue));
        return prev;
    }


/**
 * 以原子的方式给指定对象的volatile字段加1,并返回旧值,可以理解为volatile字段++
 */
public int getAndIncrement(T obj) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev + 1;
        } while (!compareAndSet(obj, prev, next));
        return prev;
}
/**
 * 以原子的方式给指定对象的volatile字段减1,并返回旧值,可以理解为volatile字段--
 */
public int getAndDecrement(T obj) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev - 1;
        } while (!compareAndSet(obj, prev, next));
        return prev;
    }


/**
 * 以原子的方式给指定对象的volatile字段加上delta,并返回旧值
 */
public int getAndAdd(T obj, int delta) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev + delta;
        } while (!compareAndSet(obj, prev, next));
        return prev;
    }

/**
 * 以原子的方式给指定对象的volatile字段加1,并返回新值,可以理解为++volatile字段
 */
public int incrementAndGet(T obj) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev + 1;
        } while (!compareAndSet(obj, prev, next));
        return next;
    }

/**
 * 以原子的方式给指定对象的volatile字段减1,并返回新值,可以理解为--volatile字段
 */
public int decrementAndGet(T obj) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev - 1;
        } while (!compareAndSet(obj, prev, next));
        return next;
    }


/**
 * 以原子的方式给指定对象的volatile字段加上delta,并返回新值
 */
public int addAndGet(T obj, int delta) {
        int prev, next;
        do {
            prev = get(obj);
            next = prev + delta;
        } while (!compareAndSet(obj, prev, next));
        return next;
    }

/**
 * 使用给定函数,以原子方式更新指定对象的volatile字段值,并返回旧值,该函数接受当前值并计算一个 
 * 新的值
 */
public final int getAndUpdate(T obj, IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get(obj);
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(obj, prev, next));
        return prev;
    }

/**
 * 使用给定函数,以原子方式更新指定对象的volatile字段值,并返回新值,该函数接受当前值并计算一个 
 * 新的值
 */
 public final int updateAndGet(T obj, IntUnaryOperator updateFunction) {
        int prev, next;
        do {
            prev = get(obj);
            next = updateFunction.applyAsInt(prev);
        } while (!compareAndSet(obj, prev, next));
        return next;
    }
2.4.4.2 AtomicIntegerFieldUpdater常用API使用案例
public class Test {

    private static final AtomicIntegerFieldUpdater<Product> fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(Product.class, "count");

    public static void main(String[] args) {
        Product product = new Product();
        fieldUpdater.set(product, 2);
        int a = fieldUpdater.get(product);
        System.out.println("get方法获取到的值:" + a + " product对象获取到的值:" + product.getCount()); //输出2 2
        int b = fieldUpdater.getAndSet(product, 10);
        System.out.println("设置新的值,返回旧值:" + b + " 新值" + product.getCount()); //输出 2  10
        int c = fieldUpdater.getAndIncrement(product);
        System.out.println("count++:" + c + " 加1以后得值:" + product.getCount());//输出10 11
        int d = fieldUpdater.getAndDecrement(product);
        System.out.println("count--:" + d + " 加1以后得值:" + product.getCount());//输出11 10
        int e = fieldUpdater.getAndAdd(product, 10);
        System.out.println("加10以后返回的旧值" + e + " 新值" + product.getCount()); // 输出 10 20
        int f = fieldUpdater.incrementAndGet(product);
        System.out.println("++count:" + f + " 加1以后得值:" + product.getCount()); //输出 21 21
        int g = fieldUpdater.decrementAndGet(product);
        System.out.println("--count:" + g + " 减1以后得值:" + product.getCount()); //输出 20 20
        int h = fieldUpdater.addAndGet(product, 10);
        System.out.println("加10以后返回的新值:" + h + " 新值:" + product.getCount());//输出 30 30
        int i = fieldUpdater.getAndUpdate(product, x -> x + 10);
        System.out.println("函数式相加返回旧值:" + i + "新值:" + product.getCount());// 输出 30 40
        int j  = fieldUpdater.updateAndGet(product, x -> x + 10);
        System.out.println("函数式相加返回新值:" + j + "新值:" + product.getCount());// 输出 50 50
        boolean flag = fieldUpdater.compareAndSet(product,50,60);
        System.out.println("预计值一致,所以进行更新:"+flag+" 更新以后得值为:"+product.getCount()); //输出true 60
    }
}

class Product {
    volatile int count = 0;

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }
}

2.4.3 AtomicReferenceFieldUpdater介绍

AtomicReferenceFieldUpdater主要是对引用类型中被volatile修饰的字段进行原子性的操作

2.4.3.1 AtomicReferenceFieldUpdater常用API源码和注释
/**
 * 构造方法,用于创建一个新的AtomicReferenceFieldUpdater,需要指定引用类型类
 * 属性类型,字段名称
 */
public static <U,W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass,
                                                                    Class<W> vclass,
                                                                    String fieldName) {
        return new AtomicReferenceFieldUpdaterImpl<U,W>
            (tclass, vclass, fieldName, Reflection.getCallerClass());
    }

/**
 * 获取指定对象的volatile字段的当前值
 */
public abstract V get(T obj);

/**
 * 以原子方式设置指定对象的volatile字段的值为新值
 */
public abstract void set(T obj, V newValue);

/**
 * 如果当前指定对象的volatile字段的值与期望值一致,那么就进行原子性更新,并返回true,否则返回 
 * false
 */
public abstract boolean compareAndSet(T obj, int expect, int update);

/**
 * 以原子方式设置指定对象的volatile字段值为新值,并返回该字段的旧值
 */
public V getAndSet(T obj, V newValue) {
        V prev;
        do {
            prev = get(obj);
        } while (!compareAndSet(obj, prev, newValue));
        return prev;
    }
/**
 * 使用给定函数,以原子方式更新指定对象的volatile字段值,并返回旧值,该函数接受当前值并计算一个
 * 新的值
 */
public final V getAndUpdate(T obj, UnaryOperator<V> updateFunction) {
        V prev, next;
        do {
            prev = get(obj);
            next = updateFunction.apply(prev);
        } while (!compareAndSet(obj, prev, next));
        return prev;
    }

/**
 * 使用给定函数,以原子方式更新指定对象的volatile字段值,并返回新值,该函数接受当前值并计算一个
 * 新的值
 */
public final V updateAndGet(T obj, UnaryOperator<V> updateFunction) {
        V prev, next;
        do {
            prev = get(obj);
            next = updateFunction.apply(prev);
        } while (!compareAndSet(obj, prev, next));
        return next;
    }
2.4.3.2 AtomicReferenceFieldUpdater常用API使用案例
public class Test {

    private static final AtomicReferenceFieldUpdater<Product,Integer> fieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Product.class, Integer.class,"count");

    public static void main(String[] args) {
        Product product = new Product();
        fieldUpdater.set(product, 2);
        int a = fieldUpdater.get(product);
        System.out.println("get方法获取到的值:" + a + " product对象获取到的值:" + product.getCount()); //输出2 2
        int b = fieldUpdater.getAndSet(product, 10);
        System.out.println("设置新的值,返回旧值:" + b + " 新值" + product.getCount()); //输出 2  10
        int i = fieldUpdater.getAndUpdate(product, x -> x + 10);
        System.out.println("函数式相加返回旧值:" + i + "新值:" + product.getCount());// 输出 10 20
        int j  = fieldUpdater.updateAndGet(product, x -> x + 10);
        System.out.println("函数式相加返回新值:" + j + "新值:" + product.getCount());// 输出 30 30
        boolean flag = fieldUpdater.compareAndSet(product,30,60);
        System.out.println("预计值一致,所以进行更新:"+flag+" 更新以后得值为:"+product.getCount()); //输出true 60
    }
}

class Product {
    volatile Integer count = 0;

    public Integer getCount() {
        return count;
    }

    public void setCount(Integer count) {
        this.count = count;
    }
}

参考文档:

 Java-Atomic-原子类-总结_java atomic-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1845817.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MVC模式中控制器、视图和模型之间的关系如何?

mvc模式将应用程序逻辑与表示层分离&#xff0c;包括控制器、视图和模型三个组件&#xff1a;控制器&#xff1a;协调用户输入&#xff0c;获取模型数据&#xff0c;验证输入&#xff0c;执行业务规则。视图&#xff1a;显示模型数据&#xff0c;不包含业务逻辑。模型&#xff…

大厂薪资福利篇第三弹:阿里巴巴

为什么计算机学子对大厂趋之若鹜呢&#xff1f;最直接的原因就是高薪资的吸引力。 • 但是薪资可不是简单的数字哦&#xff0c;里面还是有很多“学问”的。 • 很多同学对大厂薪资只有一个模糊的了解&#xff0c;知道大厂的年薪高达三十四十万甚至五十万&#xff0c;但是对具体…

【鸿蒙】HUAWEI DevEco Studio安装

HUAWEI DevEco Studio介绍 面向HarmonyOS应用及元服务开发者提供的集成开发环境(IDE)&#xff0c; 助力高效开发。 DevEco Studio当前最新版本是&#xff1a; 3.1。 DevEco Studio计划里程碑 版本类型说明 下载 下载网址&#xff1a;DevEco Studio安装包官⽅下载 双击运行…

Linux_理解进程地址空间和页表

目录 1、进程地址空间示意图 2、验证进程地址空间的结构 3、验证进程地址空间是虚拟地址 4、页表-虚拟地址与物理地址 5、什么是进程地址空间 6、进程地址空间和页表的存在意义 6.1 原因一&#xff08;效率性&#xff09; 6.2 原因二&#xff08;安全性&#xff09; …

【CT】LeetCode手撕—236. 二叉树的最近公共祖先

目录 题目1- 思路2- 实现⭐236. 二叉树的最近公共祖先——题解思路 3- ACM实现 题目 原题连接&#xff1a;236. 二叉树的最近公共祖先 1- 思路 模式识别 模式1&#xff1a;二叉树最近公共祖先 ——> 递归 判断 递归思路&#xff0c;分情况判断&#xff1a; 1.参数及返…

【IEEE独立出版、有确定的ISBN号】第三届能源与电力系统国际学术会议 (ICEEPS 2024)

第三届能源与电力系统国际学术会议 (ICEEPS 2024) 2024 3rd International Conference on Energy and Electrical Power Systems 连续2届会后4-5个月EI检索&#xff0c;检索稳定&#xff01; 成功申请IEEE出版&#xff01; 特邀院士、Fellow 报告&#xff01; 一、大会信息 …

nexus配置问题

错误信息&#xff1a; npm ERR! code E401 npm ERR! Unable to authenticate, need: BASIC realm"Sonatype Nexus Repository Manager"解决办法一&#xff1a; npm login --registryhttp://192.168.52.128:8081/repository/npm-repo 输入 用户名 密码 邮箱完成后会…

用Python执行JavaScript代码,这些方法你不可不知!

目录 1、PyExecJS:轻量级桥梁 🌉 1.1 安装与配置 1.2 执行JS代码示例 1.3 案例:数据交互与转换 1.4 错误处理与性能考量 2、Node.js子进程 🌀 2.1 准备工作:安装Node.js 2.1 利用subprocess模块 2.2 实时数据交换技巧 2.3 实战:跨语言API调用 3、Selenium驱…

【vue scrollTo 数据无限滚动 】

vue数据无限滚动 参考来源 Vue3 实现消息无限滚动的新思路 —— 林三心不学挖掘机 vue3代码 <template><div class"scroll-container" ref"scrollRef"><div v-for"(item, index) in list" :key"index" style"hei…

基于Sringboot+Vue的校园招聘系统【原创】【开源】

浏览器&#xff1a;Chrome或360浏览器 系统环境配置 前置条件&#xff1a;系统已经安装了Mysql5.7、Mysql工具&#xff08;Navicat&#xff09;、JDK1.8、Maven3.6.1、vue3.0以下开发环境、 Intellij Idea、 Chrome或360浏览器 1、导入数据库 2、编译前端代码vue 编译&…

帮企商城10合一万能DIY分销商城小程序源码系统 带源代码包+搭建部署教程

系统概述 这是一款集多种功能于一体的源码系统&#xff0c;旨在为用户提供一站式的商城解决方案。它不仅支持小程序端&#xff0c;还能与其他平台无缝对接&#xff0c;满足不同用户的需求。 代码示例 系统特色功能一览 1.万能 DIY 功能&#xff1a;用户可以根据自己的需求和创…

视频云沉浸式音视频技术能力探索与建设

概述 随着传输技术、显示技术与算力的持续提升&#xff0c;用户对于音视频体验的需求在提高&#xff0c;各家设备厂商也在探索和推出对应的技术与产品。打造空间感的空间视频与空间音频是其中最为关键的2项技术&#xff0c;bilibili视频云在这两项技术领域也进行了相关代探索与…

足底筋膜炎的症状

足底筋膜炎是足底的肌腱或者筋膜发生无菌性炎症所致&#xff0c;其症状主要包括&#xff1a; 1、疼痛&#xff1a;这是足底筋膜炎最常见和突出的症状。疼痛通常出现在足跟或足底近足跟处&#xff0c;有时压痛较剧烈且持续存在。晨起时或长时间不活动后&#xff0c;疼痛感觉尤为…

计算机系统基础(一)

1. 引入——从源程序到可执行文件 了解高级语言编写的代码在后台是如何被编译并运行的 首先我们会编写一段代码&#xff0c;例如 #include<stdio.h>int main(){printf("hello world!\n");return 0; } 并把它命名为hello.c文件 预处理阶段 接下来通过命令…

数据结构--单链表(图文)

单链表的概念 在单链表中&#xff0c;每个元素&#xff08;称为节点&#xff09;包含两部分&#xff1a;一部分是存储数据的数据域&#xff0c;另一部分是存储下一个节点地址的指针域。这里的“单”指的是每个节点只有一个指向下一个节点的指针。 节点&#xff1a;链表中的基…

网络协议安全:TCP/IP协议栈的安全问题和解决方案

「作者简介」:北京冬奥会网络安全中国代表队,CSDN Top100,就职奇安信多年,以实战工作为基础对安全知识体系进行总结与归纳,著作适用于快速入门的 《网络安全自学教程》,内容涵盖Web安全、系统安全等12个知识域的一百多个知识点,持续更新。 这一章节我们需要知道TCP/IP每…

2024最新最全【网络安全/渗透测试】面试题汇总

思路流程 信息收集漏洞挖掘漏洞利用&权限提升清除测试数据&输出报告复测 问题深信服一面:SQL注入防护为什么参数化查询可以防止sql注入SQL头注入点盲注是什么&#xff1f;怎么盲注&#xff1f;宽字节注入产生原理以及根本原因 产生原理在哪里编码根本原因解决办法sql里…

Kafka中的时间轮算法

1. Kafka与时间轮&#xff1a; Kafka的定时器底层使用时间轮算法。Kafka时间轮是层次时间轮&#xff0c;并且支持时间轮复用。 优点&#xff1a; 高效的插入操作&#xff1a; 时间轮底层数据结构&#xff08;桶&#xff09;&#xff0c;使用双向链表的设计使得插入操作的时间…

掌握JavaScript ES6精髓:探索函数和对象的高级扩展与实用技巧

序言 JavaScript&#xff0c;作为前端开发中不可或缺的语言&#xff0c;已经发展到了ECMAScript 2015&#xff08;简称ES6&#xff09;以及后续的版本。ES6带来了诸多语法上的改进和创新&#xff0c;使得代码更加简洁、优雅&#xff0c;同时也提供了更多的编程模式和实用技巧。…

Python-面向对象编程(超详细易懂)

面向对象编程&#xff08;oop&#xff09; 面向对象是Python最重要的特性&#xff0c;在Python中一切数据类型都是面向对象的。 面向对象的编程思想&#xff1a;按照真实世界客观事物的自然规律进行分析&#xff0c;客观世界中存在什么样的实体&#xff0c;构建的软件系统就存在…