Java并发编程之原子操作类详情

 更新时间:2022年04月15日 17:58:24   作者:派大大大星   
这篇文章主要介绍了Java并发编程之原子操作类详情,文章基于Java并发编程展开相关内容,具有一定的参考价值,需要的小伙伴可以参考一下

JUC包提供了一系列的原子性操作类,这些类都是使用非阻塞算法CAS实现的,相比使用锁实现原子性操作者在性能上有很大提升。JUC包中含有AtomicInteger、AtomicLong、AtomicBoolean,它们的原理类似。下面我们以AtomicLong为例来讲解。

我们先来看一下部分源码:

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

    //1.获取Unsafe类实例
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    //2.存放value的偏移量
    private static final long valueOffset;
    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

    //3.用于判断是否支持Long类型无锁CAS
    private static native boolean VMSupportsCS8();

    static {
        try {
            //4.获取value在AtomicLong中的偏移量
            valueOffset = unsafe.objectFieldOffset
                (AtomicLong.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }
    //5.实际变量值
    private volatile long value;

    /**
     * Creates a new AtomicLong with the given initial value.
     *
     * @param initialValue the initial value
     */
    public AtomicLong(long initialValue) {
        value = initialValue;
    }
    ············省略部分代码·············
}

上面代码中,代码1处通过Unsafe.getUnsafe()获取到Unsafe类的实例(因为AtomicLong类是在rt.jar包下面的,AtomicLong类就是通过Bootstarp类加载器进行加载的)。代码5处,value被声明为volatile类型,保证内存的可见性。通过代码2,4获取value变量在AtomicLong类中的偏移量。

接下来介绍一下AtomicLong中的主要函数:

  • 递增和递减代码
//调用unsafe方法,设置value=value+1后,返回原始的值
public final long getAndIncrement() {
    return unsafe.getAndAddLong(this, valueOffset, 1L);
}

//调用unsafe方法,设置value=value-1后,返回原始的值
public final long getAndDecrement() {
    return unsafe.getAndAddLong(this, valueOffset, -1L);
}


//调用unsafe方法,设置value=value+1后,返回递增后的值
public final long incrementAndGet() {
    return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
}

//调用unsafe方法,设置value=value-1后,返回递减后的值
public final long decrementAndGet() {
    return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;
}

上面的四个函数内部都是通过调用Unsafe的getAndAddLong方法来实现操作,这个函数是个原子性操作,这里第一个参数是AtomicLong实例的引用的,第二个参数是value变量在AtomicLong的偏移值,第三个参数是要设置的第二个变量的值。

其中getAndIncrement()方法在JDK7中实现逻辑为:

public final long getAndIncrement() {
    while(true) {
        long current = get();
        long next = current + 1;
        if (compareAndSet(current, next))
            return current;
    }
}

如上代码中,每个线程是先拿到变量的当前值(由于value是volatile变量,所以这是获取的最新值),然后在工作内存中对其进行增1操作,而后使用CAS修改变量的值,如果设置失败,则循环继续尝试,直到设置成功。

JDK8中的逻辑为:

public final long getAndIncrement() {
        retrturn unsafe.getAndAddLong(this, valueOffset, 1L);
    }

其中JDK8中的unsafe.getAndAddLong的代码为:

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;
}

从中可以看到,JDK7中的AtomicLong中循环逻辑已经被JDK8中的原子操作类Unsafe内置了。

  • boolean compareAndSet(long expect,long update)
public final boolean compareAndSet(long expect,long update) 
{
    return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}

函数在内部调用了unsafe.compareAndSwapLong方法。如果原子变量中的value值等于expect,则使用update值更新该值并返回true,否则返回false。

到此这篇关于Java并发编程之原子操作类详情的文章就介绍到这了,更多相关Java 原子操作类内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 解决Mybatis mappe同时传递 List 和其他参数报错的问题

    解决Mybatis mappe同时传递 List 和其他参数报错的问题

    在使用MyBatis时,如果需要传递多个参数到SQL中,可以遇到参数绑定问题,解决方法包括使用@Param注解和修改mapper.xml配置,感兴趣的朋友跟随小编一起看看吧
    2024-09-09
  • Spring Boot对Future模式的支持详解

    Spring Boot对Future模式的支持详解

    这篇文章主要给大家介绍了关于Spring Boot对Future模式的支持的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用spring boot具有一定的参考学习价值,需要的朋友们下面来一起看看吧
    2019-01-01
  • Java实现获取小程序带参二维码并保存到本地

    Java实现获取小程序带参二维码并保存到本地

    这篇文章主要介绍了Java实现获取小程序带参二维码并保存到本地,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Java动态规划之硬币找零问题实现示例

    Java动态规划之硬币找零问题实现示例

    本文主要介绍了Java动态规划之硬币找零问题实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • idea启动Tomcat时控制台乱码的解决方法(亲测有效)

    idea启动Tomcat时控制台乱码的解决方法(亲测有效)

    最近在idea中启动tomcat出现控制台乱码问题,尝试了很多方法,最后终于解决了,所以下面这篇文章主要给大家介绍了关于idea启动Tomcat时控制台乱码的解决方法,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • IDEA使用properties配置文件进行mysql数据库连接的教程图解

    IDEA使用properties配置文件进行mysql数据库连接的教程图解

    Properties类是 键和值均为字符串的可以永久存储到文件中的key-value集合。这篇文章主要介绍了IDEA使用properties配置文件进行mysql数据路连接 ,需要的朋友可以参考下
    2018-10-10
  • Quartz中的Job与JobDetail解析

    Quartz中的Job与JobDetail解析

    这篇文章主要介绍了Quartz中的Job与JobDetail解析,你定义了一个实现Job接口的类,这个类仅仅表明该job需要完成什么类型的任务,除此之外,Quartz还需要知道该Job实例所包含的属性;这将由JobDetail类来完成,需要的朋友可以参考下
    2023-11-11
  • Java多线程实现FTP批量上传文件

    Java多线程实现FTP批量上传文件

    这篇文章主要为大家详细介绍了Java多线程实现FTP批量上传文件,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • java使用SFTP上传文件到资源服务器

    java使用SFTP上传文件到资源服务器

    这篇文章主要介绍了java使用SFTP上传文件到资源服务器,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • 通俗讲解JVM的类加载机制

    通俗讲解JVM的类加载机制

    这篇文章主要介绍了JVM的类加载机制的相关资料,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-09-09

最新评论