Java并发 - 原子类

本文详细介绍了CAS(CompareandSwap)原子操作在并发编程中的应用,包括其基本原理、优点、缺点以及AtomicInteger、AtomicBoolean、AtomicReference和AtomicStampedReference等原子类的使用示例。同时提到了Unsafe类的底层操作及其限制。
摘要由CSDN通过智能技术生成

CAS 原子操作

CAS(Compare and Swap)是一种并发算法,通常用于实现多线程环境下的同步操作,特别是在并发编程中实现无锁算法。CAS操作涉及三个参数:内存位置(V)、期望值(A)和新值(B)。操作的意义是:仅当V的值等于A时,才将V的值更新为B。整个操作是原子的,不会被其他线程中断。

下面是CAS的基本原理:

  1. 读取内存值(V): 线程首先读取共享变量的当前值(V)。
  2. 比较并交换(Compare and Swap): 线程比较读取的值(V)与预期的值(A)。如果相等,说明在读取值的过程中没有其他线程对该变量进行修改,那么线程将新值(B)写入内存位置;否则,说明有其他线程对该变量进行了修改,CAS操作失败,线程需要重新尝试。
  3. 原子性保证: 整个比较并交换的过程是原子性的,即在整个操作过程中,不会被其他线程中断。

CAS优点:

​ 避免了使用锁带来的性能开销,因为它不会使线程阻塞,而是采用乐观的方式尝试更新共享变量

CAS缺点:

  1. ABA问题: 如果一个变量原来的值是A,线程1将其改为B,然后又改回A,此时线程2通过CAS检查发现值仍然是A,认为没有被修改,但实际上已经发生了变化。为了解决ABA问题,可以使用版本号等方式引入更多信息。
  2. 循环时间长开销大:CAS操作失败时,线程需要不断地重试,直到成功为止。这可能导致一些线程长时间无法完成操作,增加了开销。
  3. 只能保证一个共享变量的原子操作: CAS只能对单一的共享变量进行原子操作,无法支持类似于整个事务的复合操作。

CAS 示例

public class CASExample {
    public static void main(String[] args) {
        // 创建一个AtomicInteger,初始值为0
        AtomicInteger atomicInteger = new AtomicInteger(0);
        // 执行CAS操作,尝试将值从0更新为1
        boolean casResult = atomicInteger.compareAndSet(0, 1);

        if (casResult) {
            System.out.println("CAS success. new value: " + atomicInteger.get());
        } else {
            System.out.println("CAS failed.");
        }
        // 尝试再次执行CAS操作,将值从0更新为2,但由于当前值已经是1,操作会失败
        casResult = atomicInteger.compareAndSet(0, 2);

        if (casResult) {
            System.out.println("CAS successful. new value: " + atomicInteger.get());
        } else {
            System.out.println("CAS failed.");
        }
    }
}
Connected to the target VM, address: '127.0.0.1:64335', transport: 'socket'
CAS success. new value: 1
CAS failed.

UnSafe 原子操作

Unsafe 类是 Java 中的一个非常特殊且强大的类,它提供了直接访问内存和执行 CAS(Compare and Swap)等底层操作的方法。然而,Unsafe 类并不是官方公开的 API,并且在 Java 9 中进行了限制,不再推荐使用。因此,如果可能,最好避免直接使用 Unsafe 类。

以下是一些 Unsafe 类的主要功能:

  1. 内存操作: Unsafe 类提供了一些方法,可以直接操作内存,如allocateMemoryfreeMemoryputXXXgetXXX 等方法,其中 XXX 表示不同的数据类型。
  2. 对象操作: Unsafe 类允许直接操作对象的内部字段,比如获取和设置字段的值,甚至可以直接修改对象的类。这些操作可能绕过了 Java 的访问权限检查。
  3. CAS 操作: Unsafe 类提供了 CAS 相关的方法,例如 compareAndSwapIntcompareAndSwapLongcompareAndSwapObject 等,用于实现无锁算法。
  4. 数组操作: Unsafe 提供了一系列用于操作数组元素的方法,例如 putIntVolatilegetIntVolatile 等。
  5. 类加载: Unsafe 类还提供了一些用于加载类和定义类的方法。

AtomicInteger

AtomicInteger 是一种用于执行原子操作的整型类。它常用于在多线程环境下对计数器进行操作。

int get() 				// 获取当前 AtomicInteger 对象的当前值。
void set(int newValue) 	// 设置 AtomicInteger 对象的值为指定的新值。
int getAndIncrement()   // 原子性地将当前值加 1,并返回加 1 前的值
int incrementAndGet()   // 原子性地将当前值加 1,并返回加 1 后的值。
boolean compareAndSet(int expect, int update)   // 如果当前值等于预期值 expect,则将当前值更新为新值 update,返回更新是否成功的结果。
int addAndGet(int delta)// 原子性地将当前值与给定的增量 delta 相加,并返回相加后的值。
void lazySet(int newValue) //使用lazySet设置值后,其他线程可能会在之后的一小段时间内读到的还是旧值,更新为newValue有延迟。

AtomicInteger使用示例

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerExample {
    public static void main(String[] args) {
        AtomicInteger counter = new AtomicInteger(0);

        // 原子性地增加计数器值
        int incrementedValue = counter.incrementAndGet();
        System.out.println("Incremented Value: " + incrementedValue);
    }
}

AtomicBoolean

AtomicBoolean 提供对布尔类型变量的原子操作,通常用于在多线程环境下实现一些状态标记。

// 获取当前 AtomicBoolean 对象的当前值。
boolean get()
// 设置 AtomicBoolean 对象的值为指定的新值。
void set(boolean newValue)
// 原子性地设置 AtomicBoolean 对象的新值,并返回设置前的旧值。
boolean getAndSet(boolean newValue)
// 如果当前值等于预期值 expect,则将当前值更新为新值 update,返回更新是否成功的结果。
boolean compareAndSet(boolean expect, boolean update)
// 与 compareAndSet 方法类似,但不一定提供强制的内存同步。
boolean weakCompareAndSet(boolean expect, boolean update)

AtomicBoolean使用示例

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanExample {
    public static void main(String[] args) {
        AtomicBoolean flag = new AtomicBoolean(true);

        // 原子性地将标志值设置为false
        flag.compareAndSet(true, false);
        System.out.println("Flag Value: " + flag.get());
    }
}

AtomicReference

AtomicReference 允许原子性地操作引用类型变量。下面是一个示例,演示如何原子性地更新引用值

AtomicReference(V initialValue) // 构造函数,创建一个AtomicReference实例,初始值为initialValue。
V get()	// 获取当前引用的值。
void set(V newValue)	// 设置当前引用的值为newValue。
boolean compareAndSet(V expect, V update)	// 如果当前引用的值等于expect,则将当前引用的值设置为update,返回true;否则,返回false。
V getAndSet(V newValue)	// 设置当前引用的值为newValue,并返回先前的值。
boolean weakCompareAndSet(V expect, V update)	// 类似于compareAndSet,但是对于某些实现,不保证对 expect 和 update 的原子性检查。
String toString() // 返回当前引用的字符串表示形式。

AtomicReference使用示例

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceExample {
    public static void main(String[] args) {
        AtomicReference<String> reference = new AtomicReference<>("initialValue");

        // 如果当前值为"initialValue",则设置为"newValue"
        reference.compareAndSet("initialValue", "newValue");

        System.out.println("Reference Value: " + reference.get());
    }
}

AtomicStampedReference

AtomicStampedReferenceAtomicReference 的基础上增加了版本号,用于解决ABA问题。

// 构造方法
AtomicStampedReference(V initialRef, int initialStamp)
// 返回当前引用
V getReference()
// 返回当前标记
int getStamp()
// 返回当前引用,并将当前标记存储在 stampHolder[0] 中
V get(int[] stampHolder)
// 如果当前引用和标记与 expectedReference、expectedStamp 相等,则使用 newReference 和 newStamp 更新引用和标记。该方法在CAS操作的基础上进行判断,避免了ABA问题。
boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)
// 与 compareAndSet 方法相同,但被声明为 weak,通常在不需要保证线程间同步的场景使用。
boolean weakCompareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp)

AtomicStampedReference使用示例

import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampedReferenceExample {
    public static void main(String[] args) {
        AtomicStampedReference<String> stampedReference = new AtomicStampedReference<>("initialValue", 0);
        
        // 如果当前值为"initialValue"且版本号为0,则设置为"newValue"和版本号1
        stampedReference.compareAndSet("initialValue", "newValue", 0, 1);
        
        System.out.println("Stamped Reference Value: " + stampedReference.getReference());
        System.out.println("Stamped Reference Stamp: " + stampedReference.getStamp());
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

--土拨鼠--

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值