当前位置: 首页 > article >正文

并发编程之Atomic原子操作类

基本类型:AtomicInteger、AtomicBoolean、AtomicLong

引用类型:AtomicReference、AtomicMarkableReference、AtomicStampedReference

数组类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

对象属性原子修改器:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater

原子类型累加器:DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64

1. 基本类型

以AtomicInteger为例,它提供了原子计数器和比较交换功能

1.1 原子计数器

addAndGet()- 以原子方式将给定值添加到当前值,并在添加后返回新值。
getAndAdd() - 以原子方式将给定值添加到当前值并返回旧值。
incrementAndGet()- 以原子方式将当前值递增1并在递增后返回新值。它相当于i ++操作。
getAndIncrement() - 以原子方式递增当前值并返回旧值。它相当于++ i操作。
decrementAndGet()- 原子地将当前值减1并在减量后返回新值。它等同于i-操作。
getAndDecrement() - 以原子方式递减当前值并返回旧值。它相当于-i操作。

使用示例:

package org.example.concurrent;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class AtomicIntegerTest {
    @Test
    public void test() {
        AtomicInteger atomic = new AtomicInteger(0);
        log.debug("atomic={}", atomic);
        log.debug("atomic.addAndGet(1)={}, atomic={}", atomic.addAndGet(1), atomic);
        log.debug("atomic.getAndAdd(1)={}, atomic={}", atomic.getAndAdd(1), atomic);
        log.debug("atomic.incrementAndGet()={}, atomic={}", atomic.incrementAndGet(), atomic);
        log.debug("atomic.getAndIncrement()={}, atomic={}", atomic.getAndIncrement(), atomic);
        log.debug("atomic.decrementAndGet()={}, atomic={}", atomic.decrementAndGet(), atomic);
        log.debug("atomic.getAndDecrement()={}, atomic={}", atomic.getAndDecrement(), atomic);
    }
}

打印结果:

18:34:38.578 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic=0
18:34:38.581 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic.addAndGet(1)=1, atomic=1
18:34:38.581 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic.getAndAdd(1)=1, atomic=2
18:34:38.581 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic.incrementAndGet()=3, atomic=3
18:34:38.581 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic.getAndIncrement()=3, atomic=4
18:34:38.581 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic.decrementAndGet()=3, atomic=3
18:34:38.581 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic.getAndDecrement()=3, atomic=2

1.2 比较和交换功能

   比较和交换操作将内存中的内容与给定值进行比较,并且只有它们相同时,才将该内存位置的内容修改为给定的新值。这是作为单个原子操作完成的。

boolean compareAndSet(int expect, int update);//设置成功返回true,否则返回false

代码示例:

package org.example.concurrent;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class AtomicIntegerTest {
    @Test
    public void test() {
        AtomicInteger atomic = new AtomicInteger(0);
        log.debug("atomic={}, atomic.compareAndSet(0, 22) = {}", atomic.get(),
                atomic.compareAndSet(0, 22));

        // atomic中的值已经为22, 下面的修改会失败
        log.debug("atomic={}, atomic.compareAndSet(0, 22) = {}", atomic.get(),
                atomic.compareAndSet(0, 22));
    }
}

打印结果:

19:03:32.844 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic=0, atomic.compareAndSet(0, 22) = true
19:03:32.847 [main] DEBUG o.e.concurrent.AtomicIntegerTest - atomic=22, atomic.compareAndSet(0, 22) = false

2. 引用类型

2.1 AtomicReference

    原子引用可以保证你在修改引用的对象时(引用对象1改为引用对象2)的线程安全性。compareAndSet比较的是否是相同的对象,不是调用对象的equal比较

示例:

package org.example.concurrent;

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicReference;

@Slf4j
public class AtomicReferenceTest {
    @Test
    public void test() {
        Person person1 = new Person("张三");
        Person person2 = new Person("李四");
        AtomicReference<Person> atomic = new AtomicReference<>(person1);
        log.debug("atomic={}, atomic.compareAndSet({}, {}) = {}", atomic.get(), person1, person2,
                atomic.compareAndSet(person1, person2));

        log.debug("atomic={}, atomic.compareAndSet({}, {}) = {}", atomic.get(), person1, person2,
                atomic.compareAndSet(person1, person2));

        // 创建一个新的李四对象,设置仍然失败
        log.debug("atomic={}, atomic.compareAndSet({}, {}) = {}", atomic.get(), person2, person1,
                atomic.compareAndSet(new Person("李四"), person1));
    }

    @AllArgsConstructor
    @Getter
    @EqualsAndHashCode
    public static class Person {
        private final String name;

        @Override
        public String toString() {
            return getName();
        }
    }
}

打印结果:

19:01:21.260 [main] DEBUG o.e.concurrent.AtomicReferenceTest - atomic=张三, atomic.compareAndSet(张三, 李四) = true
19:01:21.263 [main] DEBUG o.e.concurrent.AtomicReferenceTest - atomic=李四, atomic.compareAndSet(张三, 李四) = false
19:01:21.263 [main] DEBUG o.e.concurrent.AtomicReferenceTest - atomic=李四, atomic.compareAndSet(李四, 张三) = false

2.2 AtomicMarkableReference 带标记的原子引用

    标记只能携带true和false两个值。提供的方法有:

  1.   getReference() 获取当前引用的对象
  2.   isMarked() 返回标记的值
  3. compareAndSet(refer, newRefer, mark, newMark),引用对象和标记都相同时,重新设置引用和标记,返回更新成功/失败

  4. boolean attemptMark(ref, newMark), 引用对象相同时,更新标记,返回跟新成功/失败

代码示例:

package org.example.concurrent;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicMarkableReference;

@Slf4j
public class AtomicMarkableReferenceTest {
    @Test
    public void test() {
        AtomicMarkableReference<String> atomic = new AtomicMarkableReference<>("abc", true);
        log.debug("reference = {}, mark={}", atomic.getReference(), atomic.isMarked());
        log.debug("atomic.compareAndSet(\"abc\",\"def\", false, true) = {}",
                atomic.compareAndSet("abc", "def", false, true));
        log.debug("atomic.compareAndSet(\"abc\",\"def\", false, true) = {}",
                atomic.compareAndSet("abc", "def", true, true));
        log.debug("reference = {}, mark={}", atomic.getReference(), atomic.isMarked());
        log.debug("atomic.attemptMark(\"def\", false) = {}, atomicMark={}",
                atomic.attemptMark("def", false), atomic.isMarked());
    }
}

执行结果:

19:48:27.319 [main] DEBUG o.e.c.AtomicMarkableReferenceTest - reference = abc, mark=true
19:48:27.322 [main] DEBUG o.e.c.AtomicMarkableReferenceTest - atomic.compareAndSet("abc","def", false, true) = false
19:48:27.322 [main] DEBUG o.e.c.AtomicMarkableReferenceTest - atomic.compareAndSet("abc","def", false, true) = true
19:48:27.322 [main] DEBUG o.e.c.AtomicMarkableReferenceTest - reference = def, mark=true
19:48:27.322 [main] DEBUG o.e.c.AtomicMarkableReferenceTest - atomic.attemptMark("def", false) = true, atomicMark=false

2.3 AtomicStampedReference带版本号的原子引用

    AtomicStampedReference 和 AtomicMarkableReference类似,只不过标记由boolean改为了int,方法attemptMark变为了attemptStamp;方法isMarked变为了getStamp

3. 数组类型

AtomicIntegerArray对数组元素的操作是原子的,提供基于数组下标的get,set,compareAndSet等操作。创建时需要提供操作的数组或者指定数组的大小。

package org.example.concurrent;

import lombok.extern.slf4j.Slf4j;
import org.junit.Test;

import java.util.concurrent.atomic.AtomicIntegerArray;

@Slf4j
public class AtomicIntegerArrayTest {
    @Test
    public void test() {
        // 创建有10个元素的数组
        AtomicIntegerArray atomic = new AtomicIntegerArray(10);
        atomic.set(0, 1); // 第0个位置设置为1
        atomic.get(0);   // 获取第0个位置的值。
        atomic.getAndAdd(2, 1); // 获取第2个位置的值,数组中的值+1
        atomic.compareAndSet(0, 1, 2); // 第0个位置的值如果时1的话,修改为2
    }
}


http://www.kler.cn/news/16712.html

相关文章:

  • 【华为OD机试真题】计算网络信号 (javaC++python)100%通过率 超详细代码注释
  • 【计算机视觉】ViT:代码逐行解读
  • linux入门---软硬链接
  • 支持轴体热插拔的平价机械键盘,全尺寸带灯效,雷柏V700DIY上手
  • linux 设置开机启动不同方式
  • Linux系统中查看日志的命令
  • CentOS软件那么老为什么大家还要用它?
  • 为什么在马云成功前就有那么多影像留下来?
  • SpringBoot调取OpenAi接口实现ChatGpt功能
  • rac部署前配置互信
  • CUDA编程(六):代码分析与调试
  • 死信队列
  • Vue3透传Attributes
  • Crowdsoure的简单介绍
  • Android Signal 使用
  • 关于使用Notion的board做工作安排这件事
  • 『Linux』第九讲:Linux多线程详解(一)_ 线程概念 | 线程控制之线程创建 | 虚拟地址到物理地址的转换
  • 云原生技术概谈
  • 医院安全(不良)事件报告系统 PHP语言实现
  • 【华为/华三】PPP
  • springbean 并发安全
  • Vue3中如何实现数字翻牌效果?
  • Redis-哈希
  • 互联网摸鱼日报(2023-04-29)
  • Docker基本管理
  • 少儿编程scratch
  • 7-1 设计一个学生类和它的一个子类——本科生类(interface接口)
  • PyTorch机器学习与深度学习技术方法
  • 微信小程序定义模板
  • 基于松鼠算法的极限学习机(ELM)回归预测-附代码