【Java并发解析】Atomic包与CAS

原子类与作用

原子特性:一组操作时不可以被打断的,要不没进行,要不完整的完成。即使在多线程的情况下。

特点:粒度更细,更轻量。但是在高度竞争情况下效率降低。

六种原子类

在这里插入图片描述

AtomicInteger

生产实例AtomicInteger atomicInteger = new AtomicInteger();

实例具有的方法:

  • get(): 获取当前值
  • getAndSet(int val): 获取当前值,并且设置新的值
  • getAndIncrement(): 获取当前值,并且自增。A++
  • getAndDecrement(): 获取当前值,并且自减。A–
  • getAndAdd(int delta):可以加很多
  • compareAndSet(int expect, int update): CAS的操作

AtomicIntegerArray

生产实例AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray (1000);生成一个数组,这个数组中的数字都是整形,可以被原子操作更新的。

实例具有的方法:

  • get(index): 获取当前值
  • getAndSet(index,int val): 获取当前值,并且设置新的值
  • getAndIncrement(index): 获取当前值,并且自增。A++
  • getAndDecrement(index): 获取当前值,并且自减。A–
  • getAndAdd(index, int delta):可以加很多
  • compareAndSet(index, int expect, int update): CAS的操作

AtomicReference

让一个对象保持原子性。主要方法就是,compareAndSet(expect, current)

生成实例AtomicReference<?> name = new AtomicReference<>();

AtomicIntegerFiledUpdate

把普通变量升级为原子类变量。

  • 构造方法:
public class test {
    static Candidate tom;
    public static AtomicIntegerFieldUpdater<Candidate> socreUpdate = AtomicIntegerFieldUpdater
            .newUpdater(Candidate.class, "score");
    public static class Candidate{
        volatile int score;
    }
    // 之后再使用的时候,使用socreUpdate.getAndIncrement(tom);
}
  • 方法原理:
    实际上它是反射实现的,因此必须是public的变量才可以被修饰升级。并且不支持static方法,同样因为是反射。

LongAdder

是Java 8引用的,再高并发的环境下,LongAdd比AtomicLong的效率高,本质是空间换时间。

构建LongAdder counter = new LongAdd();,实例方法:.increment()。这个操作的自加比AtomicLong快。

  • 原理:AtomicLong每一次都要进行flush和refresh。 LongAdder不需要每每次都flush,而是在每个线程的内部都有一个自己的计数器,不会和其他线程的计数器冲突。内部实际上有一个base变量当不激烈时候,直接累加,否则使用Cell[]数组,各个线程分散累加到自己的槽里,最后在累加。

  • 使用场合:LongAdder使用高并发下的统计求和,方法单一;AtomicLong还有其他的方法。

CAS原理

实现不能被打断的并发操作,Compare and Swap。CAS有三个操作数:内存值V,预期值A,要修改的值B。当且仅当预期值与内存值一样,才将内存值进行修改。每次有一个

本质实现:使用CPU保证原子性。

应用场景:

  • 乐观锁,采用cas的方法实现并发
  • 并发容器:concurrentHashMap
  • 原子类:AtomicInteger,这个类加载Unsafe工具,可以直接操作内存数据。并且volatile保证可见性。Unsafe是native方法。

缺点

  • ABA问题:5改成7,7又改成5。会错误的认为没有发生修改。解决方法:在使用的时候加上时间标签,AtomicStampedReference,除了对比数值还需要对比时间戳。
  • 自旋时间比较长:高并发的场景下会消耗资源。

并发与不变性

对一个对象而言,被创建以后,状态不再修改,就是不可变的。这种对象是线程安全的,因为最多只能并发读取,但是不能修改。

final关键字

  • 作用:类防止被继承;方法防止被重写,变量防止被修改。

final修饰一个对象时候,只是保证了对象的引用地址不会发生改变,但是对象引用的内容还是可能被修改的。

修饰变量

因为final的赋值只能进行一次,因为需要准寻赋值时机。

  • final 对于类变量
    final必须被初始化赋值。1.直接定义时候,2.构造函数中this.a = a, 3.初始化代码块中。
  • final静态变量
    1、直接在等号右边赋值,2.static初始代码块赋值。
  • 方法中的final
    在使用前进行赋值即可。

修饰方法

  • 不能修饰构造方法
  • 修饰其他方法,防止被override。静态方法也是不能被重写,但是可以写一个一模一样的静态方法(JVM的静态绑定)

修饰类

典型的就是String不可以被继承。

不变性与final的关系

  • 对于基本数据类,被final修改具有不变性
  • 对于对象类型,需要该对象保证自身被创建以后,状态才会永久不可变。

注意:并不是把所有的属性都声明为final就是不可变的,可能存在对象的类型。但是代码中可以保证这个对象不会被操作(对象方法封闭发布没有发生溢出),从而实现不可变。

栈空间

把变量写在线程的内部,线程调用方法,方法内部定义的int之类的是不线程共享,因此是可以保证线程安全的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值