0%

java的原子操作类

java中的13个原子操作类

当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期待之外的值。java1.5开始提供了atomic包,可以更简单高效安全的更新一个变量。atomic类基本都是Unsafe实现的包装类

4中类型的原子更新方式:

  • 原子更新基本类型
  • 原子更新数组
  • 原子更新引用
  • 原子更新属性

原子更新基本类型

  • AtomicBoolean
  • AtomicInteger
  • AtomicLong

三个类的方法几乎一模一样,以AtomicInteger举例

  • int addAndGet(int):返回新值
  • boolean compareAndSet(int expect,int update)
  • int getAndIncrement:以原子方式加1,这里返回的是自增前的值
  • void lazySet(int):使用lazySet后,可能导致其他线程在之后的一段时间内还是可以读到旧的值
  • int getAndSet:返回旧值
/**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

原子更新数组

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray:原子更新引用数据类型的元素

常用方法

  • int addAndGet(int i,int delta):以原子方式将输入的值与数组中的索引i的元素相加
  • boolean compareAndset(int i , int expect, int update):如果当前值等于预期值,则以原子方式将数组位置i的元素设置成update值

数组通过构造方法传递进去,然后AtomicIntegerArray将数组复制一份,所以AtomicIntegerArray对内部数组进行修改时,不会影响传入的数组。

原子引用类型

如果需要更新多个变量就需要原子引用变量了

AtomicReference

AtomicReferenceFieldUpdater:原子更新引用类型里的字段。

原子更新字段类

如果需要原子的更新某个类的某个字段时,就需要使用原子更新字段类,Atomic包提供一下3个类进行原子字段更新:

  • AtomicIntegerFieldUpdater
  • AtomicLongFieldUpdater
  • AtomicStampedReference
private static AtomicIntegerFieldUpdater<User> updater = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");

    public static void main(String[] args) {

        // 设置柯南的年龄10岁
        User c = new User("conan", 10);
        // 柯南涨了一岁
        System.out.println(updater.getAndIncrement(c));
        // 查询现在的年龄
        System.out.println(c.getOld());

    }

    public static class User {
        private String name;

        public volatile int old;

        public User(String name, int old) {
            this.name = name;
            this.old = old;
        }

        public String getName() {
            return name;
        }

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

        public int getOld() {
            return old;
        }

        public void setOld(int old) {
            this.old = old;
        }
    }
  • updater方法都是抽象类,需要先使用静态方法创建一个更新器,并且设置想要的更新的类和属性。
  • 更新类的字段必须使用public volatile修饰符
~~