并发编程的艺术之读书笔记(十三)

前言:

上一部分,我们一起学习了java中的Fork/Join框架,这一部分,我们来一起学习java中的原子类

我们知道当多个线程同时更新一个变量,可能会导致更新不同步的问题,比如变量i=1,有两个线程A和B,A操作i=i+1,B操作i=i+1,预期得到i=3,结果i却等于2,那是因为A和B线程在更新i时拿到的i都是1,这就是多线程导致的不同步问题,为了解决这个问题,我们一般会使用synchronized关键字,它会保证多线程操作的同步。那么还有没有更简便的方法可以实现我们的要求呢,java从jdk1.5开始在并发包里增加了一个Atomic包,这个包下的类都是原子操作类,底层用CAS保证了操作的原子性,也就不会发生多线程下不同步的问题了。下面就来一起看一下

1. 原子更新基本类型

原子方式更新的基本类型,分为3种

  1. AtomicBoolean 原子更新布尔类型
  2. AtomicInteger 原子更新整形
  3. AtomicLong 原子更新长整型

接着我们介绍一些常用方法,以最常用的AtomicInteger为例

  • int addAndGet(int delta),原子方式将输入的值与实例中的值相加,并返回结果
  • boolean compareAndSet(int expect, int update),比较并设置值,如果输入的数值等于预期值,那么用原子方式将该值设置为输入的值
  • int getAndIncrement(),原子方式把当前值加1,返回自增前的值
  • void lazySet(int newValue),最终会设置成newValue
  • int getAndSet(int newValue),原子方式设置为newValue的值,返回旧值

2. 原子更新数组

  1. AtomicIntegerArray 原子更新整形数组
  2. AtomicLongArray 原子更新长整型数组
  3. AtomicReferenceArray 原子更新引用类型数组

主要方法如下:

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

3. 原子更新引用类型

  1. AtomicReference 原子更新引用类型
  2. AtomicReferenceFieldUpdater 原子更新引用类型里的字段
  3. AtomicMarkableReference 原子更新带有标记位的引用类型

4. 原子更新字段类

  1. AtomicIntegerFieldUpdater: 原子更新整型的字段的更新器
  2. AtomicLongFieldUpdater: 原子更新长整型字段的更新器
  3. AtomicStampedFieldUpdater: 原子更新带有版本号的引用类型
  4. AtomicReferenceFieldUpdater: 上面已经说过此处不再赘述

要想原子地更新字段类需要两步。第一步,因为原子更新字段类都是抽象类,每次使用的时候必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第二步,更新类的字段必须使用public volatile修饰。下面来演示一下

public class AtomicIntegerUpdateField {
    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 void setName(String name) {
            this.name = name;
        }

        public int getOld() {
            return old;
        }

        public void setOld(int old) {
            this.old = old;
        }
    }
}

总结

本部分我们学习了java中的原子类的概念以及使用方式,下一部分我们开始学习java的并发工具类

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值