java中的Atomic类

问题背景

在多线程环境中,我们最常遇到的问题就是变量的值进行同步。因为变量需要在多线程中进行共享,所以我们必须需要采用一定的同步机制来进行控制。

通过之前的文章,我们知道可以采用Lock的机制,当然也包括今天我们讲的Atomic类。

下面我们从两种方式来分别介绍。

Lock

在之前的文章中,我们也讲了同步的问题,我们再回顾一下。 如果定义了一个计数器如下:

public class Counter {

    int counter;

    public void increment() {
counter++;
} }

如果是在单线程环境中,上面的代码没有任何问题。但是如果在多线程环境中,counter++将会得到不同的结果。

因为虽然counter++看起来是一个原子操作,但是它实际上包含了三个操作:读数据,加一,写回数据。

我们之前的文章也讲了,如何解决这个问题:

public class LockCounter {

    private volatile int counter;

    public synchronized void increment() {
counter++;
}
}

通过加synchronized,保证同一时间只会有一个线程去读写counter变量。

通过volatile,保证所有的数据直接操作的主缓存,而不使用线程缓存。

这样虽然解决了问题,但是性能可能会受影响,因为synchronized会锁住整个LockCounter实例。

使用Atomic

通过引入低级别的原子化语义命令(比如compare-and-swap (CAS)),从而能在保证效率的同时保证原子性。

一个标准的CAS包含三个操作:

  1. 将要操作的内存地址M。
  2. 现有的变量A。
  3. 新的需要存储的变量B。

CAS将会先比较A和M中存储的值是否一致,一致则表示其他线程未对该变量进行修改,则将其替换为B。 否则不做任何操作。

使用CAS可以不用阻塞其他的线程,但是我们需要自己处理好当更新失败的情况下的业务逻辑处理情况。

Java提供了很多Atomic类,最常用的包括AtomicInteger, AtomicLong, AtomicBoolean, 和 AtomicReference.

其中的主要方法:

  1. get() – 直接中主内存中读取变量的值,类似于volatile变量。
  2. set() – 将变量写回主内存。类似于volatile变量。
  3. lazySet() – 延迟写回主内存。一种常用的情景是将引用重置为null的情况。
  4. compareAndSet() – 执行CAS操作,成功返回true,失败返回false。
  5. weakCompareAndSet() – 比较弱的CAS操作,不同的是它不执行happens-before操作,从而不保证能够读取到其他变量最新的值。

我们看下怎么用:

public class AtomicCounter {

    private final AtomicInteger counter = new AtomicInteger(0);

    public int getValue() {
return counter.get();
}
public void increment() {
while(true) {
int existingValue = getValue();
int newValue = existingValue + 1;
if(counter.compareAndSet(existingValue, newValue)) {
return;
}
}
}
}

本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/atomic

更多教程请参考 flydean的博客

java中的Atomic类的更多相关文章

  1. 【Java并发】Java中的原子操作类

    综述 JDK从1.5开始提供了java.util.concurrent.atomic包. 通过包中的原子操作类能够线程安全地更新一个变量. 包含4种类型的原子更新方式:基本类型.数组.引用.对象中字段 ...

  2. java中的原子操作类AtomicInteger及其实现原理

    /** * 一,AtomicInteger 是如何实现原子操作的呢? * * 我们先来看一下getAndIncrement的源代码: * public final int getAndIncremen ...

  3. 带有静态方法的类(java中的math类)

    带有静态方法的类通常(虽然不一定是这样)不打算被初始化. 可以用私有构造函数来限制非抽象类被初始化. 例如,java中的math类.它让构造函数标记为私有,所以你无法创建Math的实例.但Math类却 ...

  4. java中的File类

    File类 java中的File类其实和文件并没有多大关系,它更像一个对文件路径描述的类.它即可以代表某个路径下的特定文件,也可以用来表示该路径的下的所有文件,所以我们不要被它的表象所迷惑.对文件的真 ...

  5. Java基础(43):Java中的Object类与其方法(转)

    Object类 java.lang.Object java.lang包在使用的时候无需显示导入,编译时由编译器自动导入. Object类是类层次结构的根,Java中所有的类从根本上都继承自这个类. O ...

  6. java中基于TaskEngine类封装实现定时任务

    主要包括如下几个类: 文章标题:java中基于TaskEngine类封装实现定时任务 文章地址: http://blog.csdn.net/5iasp/article/details/10950529 ...

  7. Java中的Unsafe类111

    1.Unsafe类介绍 Unsafe类是在sun.misc包下,不属于Java标准.但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty.Hadoo ...

  8. Java中遍历实体类(处理MongoDB)

    在实际过程中,经常要将实体类进行封装,尤其是处理数据库的过程中:因此,对于遍历实体类能够与数据库中的一行数据对应起来. 我是使用的环境是Spring boot,访问的数据库时MongoDB 实体类遍历 ...

  9. java中遍历实体类,获取属性名和属性值

    方式一(实体类): //java中遍历实体类,获取属性名和属性值 public static void testReflect(Object model) throws Exception{ for ...

随机推荐

  1. python常用模块 以及第三方导入

    python常用模块 1模块的分类 标准模块(内置模块)( 标准库 )300 第三方模块 18万 pip install 直接通过pip安装 软件一般会被自动安装你python安装目录的这个子目录里 ...

  2. Gang Of Four的23中设计模式

    Gang Of Four的23中设计模式 标签(空格分隔): 设计模式 1. 根据目的来进行划分 根据目的进行划分可以分为创建型模式, 结构型模式和行为模式三种. 1.1 创建型模式 怎样创建对象, ...

  3. 【Redis】集群NetCore实战

    环境准备 1. Redis集群(Windows集群搭建) 启动Redis集群,给每个节点加上Title start .conf start .conf start .conf start .conf ...

  4. .net core 集成 sentry 进行异常报警

    .net core 集成 sentry 进行异常报警 Intro Sentry 是一个实时事件日志记录和汇集的平台.其专注于错误监控以及提取一切事后处理所需信息而不依赖于麻烦的用户反馈.它分为客户端和 ...

  5. 路由与交换,cisco路由器配置,静态路由

    网络是一个大型的拓扑结构,在路由表中,最重要的是管理距离和度量值 管理距离 管理距离用来确定路由的优先级.管理距离的范围是0-255之间的整数值.值越低代表优先级越高.0代表最高优先级.并且只有直连路 ...

  6. rancher 和 Kubernetes有什么区别?

    总体来说,Rancher和k8s都是用来作为容器的调度与编排系统.但是rancher不仅能够管理应用容器,更重要的一点是能够管理k8s集群.Rancher2.x底层基于k8s调度引擎,通过Ranche ...

  7. 20175110 王礼博 exp4恶意代码分析

    目录 1.基础知识 2.系统运行监控 3.恶意软件分析 4.基础问题回答 5.实践总结与体会 1. 基础知识 1.1 恶意代码的概念与分类 定义:指故意编制或设置的.对网络或系统会产生威胁或潜在威胁的 ...

  8. Struts2-学习笔记系列(13)-类型转换异常和校验器

    Struts2框架有默认的类型转换错误拦截机制,该配置在struts-default.xml中,名叫conversionError,但是想使用需要继承ActionSupport. 默认的错误提示信息是 ...

  9. 二、Python2.7的安装并与Python3.8共存

    一:Python解释器为什么要2个版本? 众所周知,Python2.7是一个过渡版本. 很多公司写的项目并不是基于最新的Python3写的,在之后进行一些项目更改的时候,Python3的语法有一些并不 ...

  10. tf.nn.sigmoid_cross_entropy_with_logits 分类

    tf.nn.sigmoid_cross_entropy_with_logits(_sentinel=None,,labels=None,logits=None,name=None) logits和la ...