并发编程之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
    }
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值