美文网首页
Java中的13个原子操作类

Java中的13个原子操作类

作者: 全栈未遂工程师 | 来源:发表于2016-08-13 16:51 被阅读221次

    JDK1.5提供了java.util.concurrent.atomic包,可以线程安全的更新一个变量。

    Atomic包里一个提供了12个类,属于4种类型的原子更新方式:

    • 原子更新基本类型
    • 原子更新数组
    • 原子更新引用
    • 原子更新属性(字段)

    原子更新基本类型类

    使用原子的方式更新基本类型。包括下面3个类:
    AtomicBoolean:boolean类型
    AtomicInteger:原子更新整形
    AtomicLong:原子更新长整形

    AtomicInteger常用方法:

    • int addAndGet(int delta):相加并返回结果
    • boolean compareAndSet(int expect, int update):如果当前值等于预期值,那么将该值设置为输入的值。
    • int getAndIncrement():返回当前值,然后将当前值加一
    • void lazySet(int newValue):最终会设置成newValue,但是在设置值之后,其他线程在一段时间内还可以读到旧的值。
    • int getAndSet(int newValue):返回当前值,然后将当前值设置成新值。
    package com.atomic;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class AtomicIntegerTest {
        static AtomicInteger ai = new AtomicInteger(1);
        
        public static void main(String[] args) {
            System.out.println(ai.getAndIncrement());//1
            System.out.println(ai.get());//2
        }
    }
    

    原子更新数组

    通过原子的方式更新数组中的某个元素,Atomic包提供了一下3个类:

    • AtomicIntegerArray:原子更新整形数组里的元素
    • AtomicLongArray:原子更新长整形数组里的元素
    • AtomicReferenceArray:原子更新引用类型数组里的元素

    注意:数组通过构造方法传给AtomicIntegerArray会将当前的数组复制一份,以后在复制的对象上进行操作。不会更改原来数组的值。

    AtomicIntegerArray主要提供原子的方式更新数组里的整形:

    • int addAndGet(int i, int delta):原子方式将输入值与数组里索引i的元素相加。
    • boolean compareAndSet(int i, int expect, int update):如果当前值等于预期值,则以原子方式将数组位置i的元素设置成update值
    package com.atomic;
    
    import java.util.concurrent.atomic.AtomicIntegerArray;
    
    public class AtomicIntegerArrayTest {
        static int[] value = new int[] {1,2};
        
        public static void main(String[] args) {
            AtomicIntegerArray ai = new AtomicIntegerArray(value);
            System.out.println(ai.getAndSet(0, 3));
            System.out.println(ai.get(0));
            System.out.println(value[0]);
        }
    }
    /*
    1
    3
    1
    */
    

    原子更新引用类型

    Atomic包提供了3个类:

    • AtomicReference:原子更新引用类型
    • AtomicReferenceFieldUpdater:原子更新引用类型里的字段
    • AtomicMarkableReference:原子更新带有标志位的引用类型。可以原子更新一个布尔类型的标记位和引用类型。构造方法是AtomicMarkableReference(V initialRef, boolean initialMark)
    package com.atomic;
    
    import java.util.concurrent.atomic.AtomicReference;
    
    public class AtomicReferenceTest {
        public static AtomicReference<User> atomicUserRef = new AtomicReference<User>();
        
        public static void main(String[] args) {
            User user = new User("张三",10);
            atomicUserRef.set(user);
            User updateUser = new User("李四",11);
            atomicUserRef.compareAndSet(user,  updateUser);
            System.out.println(atomicUserRef.get().getName());
            System.out.println(atomicUserRef.get().getOld());
        }
    
        static class User{
            private String name;
            private int old;
            public User(String name, int old) {
                super();
                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;
            }
        }
    }
    

    原子更新字段类

    需要原子更新某个类里的某个字段时,需要使用原子更新字段类。Atomic包提供了3个类:

    • AtomicIntegerFieldUpdate:原子更新整形的字段的更新器
    • AtomicLongFieldUpdate:原子更新长整形的字段的更新器
    • AtomicStampedReference:原子更新带有版本号的引用类型

    想要原子的更新字段类需要两步:

    1. 因为原子更新字段类都是抽象类,每次使用的时候必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。
    2. 更新类的字段必须使用public volatile修饰符。

    注意:
    被更新的字段必须是public volatile

    package com.atomic;
    
    import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
    
    public class AtomicIntegerFieldUpdaterTest {
        //创建原子更新器,并设置需要更新的类和字段
        private static AtomicIntegerFieldUpdater<User> a = AtomicIntegerFieldUpdater.newUpdater(User.class, "old");
        
        public static void main(String[] args) {
            //设置柯南10岁
            User conan = new User("conan", 10);
            //长一岁,但是还返回之前的年龄
            System.out.println(a.getAndIncrement(conan));
            //输出现在年龄
            System.out.println(a.get(conan));
        }
        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 int getOld() {
                return old;
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:Java中的13个原子操作类

          本文链接:https://www.haomeiwen.com/subject/aezesttx.html