并发编程 -- java中的原子操作

一,java中的原子操作类型

jdk1.5开始提供了Atomic包,这个包中的原子操作类提供了一种用法简单,性能高效,线程安全的更新一个变量的方式

二,原子更新基本类型

该类用于原子的更新基本类型:

  • AtomicInteger
  • AtomicBoolean
  • AtomicLong
/**
 * @Description:    原子更新基本类型
 * @Author:         Kevin
 * @CreateDate:     2019/7/1 21:34
 * @UpdateUser:     Kevin
 * @UpdateDate:     2019/7/1 21:34
 * @UpdateRemark:   修改内容
 * @Version: 1.0
 */
public class AtomicIntergerTest {

    static AtomicInteger atomicInteger = new AtomicInteger(1);
    
    public static void main(String[] args) {
        //原子的方式增加指定的值
        System.out.println("--------->" + atomicInteger.addAndGet(1));
        //compareAndSet(int expect,int update)如果expect = atomicInteger.get() 则将该atomicInteger.get()设置为update
        System.out.println("--------->"+atomicInteger.compareAndSet(1,2)+atomicInteger.get());
        //自增1,返回的是自增前的值
        System.out.println("--------->"+atomicInteger.getAndIncrement());
        //自减1,返回的是自减前的值
        System.out.println("--------->"+atomicInteger.getAndDecrement());
        //延时更新
        atomicInteger.lazySet(1);
    }
}

1.原子更新原理

1.getAndIncrement()原理

注意点:

  • atomicInteger.compareAndSet(current,next)

这是进行原子更新操作的重点,检查当前原子值是否等于current(期望值),如果相等,就是当前原子值没有被其他线程修改,可以进行更新操作

    /**
     * getAndIncrement()原理
     * @return
     */
    public static int getAndIncrement(){
        for(;;){
            //获取当前原子值
            int current = get();
            //自增
            int next = current+1;
            //如果当前原子值 == current 就将当前原子值设置为next
            if(atomicInteger.compareAndSet(current,next)){
                //返回自增前原子值
                return current;
            }
        }
    }

2.UnSafe

作用

执行低级别,不安全的操作

使用

在java程序中无法直接使用unsafe,其构造方法是私有的,我们只能通过Unsafe的getUnsafe()方法获取该类的对象:

   private static final Unsafe unsafe = Unsafe.getUnsafe();

相关具体使用:

  • 修改内存

    unsafe通过相关的putxxx 和getxxx方法来修改内存和获取内存中的值

  • 在非java堆中分配内存

    Unsafe类通过allocateMemory(long)方法分配的内存,不受Integer.MAX_VALUE的限制,并且分配在非堆内存,使用它时,需要非常谨慎,该部分内存需要手动回收,否则会产生内存泄露

  • CAS

    下面提到

3.CAS

CAS,Compare and Swap即比较并交换,设计并发算法时常用到的一种技术,java.util.concurrent包全完建立在CAS之上,没有CAS也就没有此包,可见CAS的重要性。

Unsafe类中提供了compareAndSwapObject()、compareAndSwapInt()和compareAndSwapLong()这三个方法用来实现对应的CAS原子操作。在Java的并发编程中用到的CAS操作都是调用的Unsafe类的相关方法。

unsafe中的CAS

public final native boolean compareAndSwapObject(Object o,Long offset,Object expected,Object x);

public final native boolean compareAndSwapInt(Object o,Long offset,Object expected,Object x);

public final native boolean compareAndSwapLong(Object o,Long offset,Object expected,Object x);

CAS操作原理

CAS有三个操作数:内存值V、旧的预期值A、要修改的值B,当且仅当预期值A和内存值V相同时,将内存值修改为B并返回true,否则,即内存值和当前预期值不等时,则可能是其他线程修改了当前内存值,造成线程不安全的现象,所以这时。CAS什么都不做并返回false。

三,原子更新引用类型

原子更新基本类型只能更新一个变量,如果要原子更新多个变量,就需要使用这个原子更新引用类型提供的类

  • AtomicReference 原子更新引用类型
  • AtomicReferenceFieldUpdater 原子更新引用类型里的字段
  • AtomicMarkableRefrence 原子更新带有标记位的引用类型

使用

/**
 * @Auther: Kevin
 * @Date:
 * @ClassName:AtomicReferenceTest
 * @Description: TODO
 */
public class AtomicReferenceTest {

    public static AtomicReference<User> atomicReference = new AtomicReference<>();

    public static void main(String[] args) {
        User user = new User("kevin",15);
        atomicReference.set(user);
        User updateUser = new User("newKevin",20);
        atomicReference.compareAndSet(user,updateUser);
        System.out.println("--------->"+atomicReference.get().getName());
        System.out.println("--------->"+atomicReference.get().getAge());
    }

    static class User{
        private String name;
        private int age;

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

        public String getName() {
            return name;
        }

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

        public int getAge() {
            return age;
        }

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

四,原子更新类中字段

如果需要原子地更新某个类里的某个字段时,需要使用原子更新字段类:

  • AtomicIntegerFieldUpdater
  • AtomicLongFieldUpdater
  • AtomicStampedFieldUpdater
/**
 * @Auther: Kevin
 * @Date:
 * @ClassName:AtomicIntegerFiledUpdaterTest
 * @Description: TODO
 */
public class AtomicIntegerFiledUpdaterTest {


    public static AtomicIntegerFieldUpdater<AtomicIntegerFiledUpdaterTest.User> atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(AtomicIntegerFiledUpdaterTest.User.class,"age");

    public static void main(String[] args) {
        User user = new User("kevin",20);
        System.out.println("-------->"+atomicIntegerFieldUpdater.getAndIncrement(user));
        System.out.println("--------->"+atomicIntegerFieldUpdater.get(user));
    }

    static class User{
        private String name;
        private int age;

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

        public String getName() {
            return name;
        }

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

        public int getAge() {
            return age;
        }

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

五,原子更新数组

通过原子方式来更新数组的某个元素,

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray
public class AtomicIntegerArrayTest {

    static int[] value = new int[]{1,2};

    static AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(value);

    public static void main(String[] args) {

        System.out.println("--------->"+atomicIntegerArray.addAndGet(0,2));
        System.out.println("--------->"+atomicIntegerArray.get(1));
        System.out.println("--------->"+atomicIntegerArray.getAndSet(1,2));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值