ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

02-JUC-CAS

2022-01-05 15:10:02  阅读:158  来源: 互联网

标签:02 JUC var1 var2 CAS int var5 public


CAS

JUC中多数类是通过volatile和CAS来实现的,CAS本质上提供的是一种无锁方案,而Synchronized和Lock是互斥锁方案; java原子类本质上使用的是CAS,而CAS底层是通过Unsafe类实现的。

线程安全的方法有:

  • 互斥同步:ReentrantLock 和 syschronized
  • 非阻塞同步:CAS
  • ThreadLocal

第一种方法是通过锁的方式来实现线程安全,CAS是通过无锁的方式实现的,下面重点说说CAS是如何实现线程安全的

什么是CAS

  • JUC中多数类是通过volatile和CAS来实现的,CAS本质上提供的是一种无锁方案,而Synchronized和Lock是互斥锁方案; java原子类本质上使用的是CAS,而CAS底层是通过Unsafe类实现的
  • CAS操作是原子性的,所以多线程并发使用CAS更新数据时,可以不使用锁。JDK中大量使用了CAS来更新数据而防止加锁(synchronized 重量级锁)来保持原子更新

就是有一个原值A, 如果要更新为值B,在更新前先比较原值A有没有发生变化,如果没有发生变化,就将A更新为值B,如果发生了变化就不交换

用AtomicInteger 举个小栗子:多线程情况下新增一个值

AtomicInteger a  =  new AtomicInteger(0);
public int add(){
	return a.addAndGet(1);
}

CAS 有什么问题

synchronized是通过锁来保证线程安全的,是一种悲观锁策略

而CAS是一种乐观锁策略,但是在并发问题上性能更佳,它可能会出现的问题

  • ABA问题:CAS需要在操作值的时候,检查值有没有发生变化,比如没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时则会发现它的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。比如数据表来说,可以加个version字段。不过在jdk1.5后,加了个AtomicStampedReference这个类,这个类就是利用方法compareAndSet来检查当前引用是否等于预期引用,还有标志stamp是否等于预期的标志stamp,如果都相等就更新
  • CAS自旋时间太长,会导致CPU的大的执行开销

Unsafe类

我们上面提过,很多原子类是通过Unsafe实现的,

可以看一眼Unsafe类

public final class Unsafe {
	...// 省略
  public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

    public final long getAndAddLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

        return var6;
    }

    public final int getAndSetInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var4));

        return var5;
    }

    public final long getAndSetLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);
        } while(!this.compareAndSwapLong(var1, var2, var6, var4));

        return var6;
    }

    public final Object getAndSetObject(Object var1, long var2, Object var4) {
        Object var5;
        do {
            var5 = this.getObjectVolatile(var1, var2);
        } while(!this.compareAndSwapObject(var1, var2, var5, var4));

        return var5;
    }
    ...//省略
}

可以发现,它是通过while自旋compareAndSwap进行CAS更新(如果失败就一直自旋)。里面的compareAndSwap* 都是底层的native方法

下面是Unsafe可以实现的功能(取自网络图)

比如,AtomicInteger就是通过Unsafe实现的原子性

public class AtomicInteger extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 6214790243416807050L;

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final long valueOffset;

    static {
        try {
            valueOffset = unsafe.objectFieldOffset
                (AtomicInteger.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    // volatile  值
    private volatile int value;

    /**
     * Creates a new AtomicInteger with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }
    ...//省略
   public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }

 
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }

    public final boolean weakCompareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    ...//省略
}

可以看到,value用了volatile来修饰,保证了线程的可见性,同时使用CAS来保证更新时的原子性

标签:02,JUC,var1,var2,CAS,int,var5,public
来源: https://www.cnblogs.com/volsnow/p/15767040.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有