前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >java多线程技术第N篇|AtomicInteger源码赏析

java多线程技术第N篇|AtomicInteger源码赏析

作者头像
码农王同学
发布2021-01-15 11:02:16
4200
发布2021-01-15 11:02:16
举报
文章被收录于专栏:后端Coder后端Coder

一,AtomicInteger源码赏析

1,为什么要使用原子类AtomicInteger?

好久没有进行输入了,之前很长一段时间都在输出过往的leetCode题解,但是,越输出越觉得自己心里很慌,其主要原因在于我输出的都是我已经会的了,然而我还是花了很长时间来输出了,主要是为了帮助需要的人,当然了,也是为了我自己日后看方便了很多,这不,在我输出160篇题解后,我还是找一点自己喜欢的内容,做下内容,其实也是便于自己更加的理解,这不,我来看AtomicInteger原子类的源码了。

正如开头所陈述的那样,我们为什么要是用AtomicInteger原子类?我们不妨看下下面的一段程序运行的结果吧。

代码语言:javascript
复制

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class AtomicIntegerTest {

    private static int count = 0;

    public static void main(String[] args) {
        final int cycleCount = 1000;
        CountDownLatch countDownLatch = new CountDownLatch(2);
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(() -> {
            for (int i = 0; i < cycleCount; i++) {
                count++;
            }
            countDownLatch.countDown();
        });
        executorService.submit(() -> {
            for (int i = 0; i < cycleCount; i++) {
                count++;
            }
            countDownLatch.countDown();
        });
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            log.error("中断异常:{}", e.getMessage());
            e.printStackTrace();
        }
        executorService.shutdown();
        System.out.println("count = " + count);
    }
}

上面的程序含义是,跑两个线程任务task,每个线程任务都是对成员变量count进行1000次递增操作,最终的结果应该是2000,然而,经过多次运行,结果不一定都是2000,比如下面的这种结果。

为什么会出现count不等于2000,而是其它数值呢?因为count++不是一个原子操作,count++非原子操作,那么这就是我们需要使用原子操作类AtomicInteger的原因了。

2,不使用原子操作类AtomicInteger,我们有什么可以替代的方案吗?

当然有了,那就是使用锁进行临界区资源的锁定操作,我们可以synchronized关键字绑定在方法上,也可以基于ReentrantLock锁实例对象,对需要的临界区资源进行加减锁来达到资源互斥,数据同步的效果,当然了,这两部分内容都是很多的,这里就不一一详细说明了,后面,随着内容的加深,自己会单独来举例说明一下的。

3,原子类AtomicInteger的源码方法有哪些我们需要关注的?

代码语言:javascript
复制
  (1)构造函数
    //构建一个初始值为0的原子类
    public AtomicInteger() {
    }
  (2)构造函数
    //构建一个给定初始值数据的构造函数
    public AtomicInteger(int initialValue) {
        value = initialValue;
    }
  

3.1,get()方法

代码语言:javascript
复制
//获取当前值
    public final int get() {
        return value;
    }

3.2,getAndIncrement()方法

代码语言:javascript
复制

    //返回增加1之前的数据
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }

3.3,incrementAndGet()方法

代码语言:javascript
复制
//返回增加1之后的数据,即更新后的数据
    public final int incrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
    }

3.4,decrementAndGet()方法

代码语言:javascript
复制

    //进行减一操作,获取减一后的数据
    public final int decrementAndGet() {
        return unsafe.getAndAddInt(this, valueOffset, -1) - 1;
    }

3.5,getAndDecrement()方法

代码语言:javascript
复制
//获取到减一之前的数据
    public final int getAndDecrement() {
        return unsafe.getAndAddInt(this, valueOffset, -1);
    }

4,好奇不好奇AtomicInteger原子操作类是如何数据可见的?

我们可以在类中看到成员变量value是有volatile关键字修饰的。volatile关键字修饰的内容,是可以保证内存可见性。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-01-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农王同学 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一,AtomicInteger源码赏析
    • 1,为什么要使用原子类AtomicInteger?
      • 2,不使用原子操作类AtomicInteger,我们有什么可以替代的方案吗?
        • 3,原子类AtomicInteger的源码方法有哪些我们需要关注的?
          • 3.1,get()方法
          • 3.2,getAndIncrement()方法
          • 3.3,incrementAndGet()方法
          • 3.4,decrementAndGet()方法
          • 3.5,getAndDecrement()方法
        • 4,好奇不好奇AtomicInteger原子操作类是如何数据可见的?
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档