编辑
2024-08-02
后端
00
请注意,本文编写于 281 天前,最后修改于 281 天前,其中某些信息可能已经过时。

目录

指令格式
操作原理
在多线程编程中的应用
构造方法:
获取和设置值:
原子更新操作:
常用方法
常用方法
常用方法
1. AtomicLong
常用方法
2. AtomicLongArray
常用方法
3. AtomicLongFieldUpdater
常用方法
4. LongAdder
常用方法
1. AtomicReference
常用方法
2. AtomicReferenceArray
常用方法
3. AtomicReferenceFieldUpdater
常用方法

为了避免显示使用synchronized和Lock,在某些场景我们会用cas来避免以上两者的性能开销,cas也叫做原子操作,底层通过计算机底层的cmpxchg指令来实现,cmpxchg介绍如下

指令格式

cmpxchg 指令的基本格式如下:

assembly
cmpxchg destination, source

其中:

  • destination 是目标操作数,通常是一个内存地址或寄存器。
  • source 是源操作数,通常是一个寄存器。

操作原理

cmpxchg 指令的工作原理如下:

  1. 比较:将 destination 中的值与累加器(通常是 ALAXEAX 寄存器,具体取决于操作数的大小)中的值进行比较。
  2. 交换:如果 destination 中的值等于累加器中的值,则将 source 中的值写入 destination
  3. 设置标志位:根据比较结果设置处理器的状态标志位(如 ZF 标志位)。

以下是一个简单的示例,展示如何在汇编语言中使用 cmpxchg 指令:

assembly
section .data value db 5 section .text global _start _start: mov al, 5 ; 将累加器 AL 设置为 5 mov bl, 10 ; 将寄存器 BL 设置为 10 lock cmpxchg [value], bl ; 比较并交换 ; 检查 ZF 标志位来判断操作是否成功 jz success jmp failure success: ; 操作成功 ; 在这里添加成功处理代码 jmp exit failure: ; 操作失败 ; 在这里添加失败处理代码 jmp exit exit: ; 退出程序 mov eax, 60 ; syscall: exit xor edi, edi ; status: 0 syscall

在这个示例中:

  • value 是一个内存地址,存储了一个字节值 5。
  • al 寄存器被设置为 5,bl 寄存器被设置为 10。
  • lock cmpxchg [value], bl 指令将 value 中的值与 al 中的值进行比较,如果相等,则将 bl 中的值 10 写入 value
  • 根据 ZF 标志位的状态,程序会跳转到 successfailure 标签进行相应的处理。

在多线程编程中的应用

cmpxchg 指令在多线程编程中非常有用,特别是在实现无锁数据结构时。Java 中的 AtomicInteger 类就是基于 CAS 操作实现的,而 CAS 操作通常使用 cmpxchg 指令来实现。

java
import java.util.concurrent.atomic.AtomicInteger; public class AtomicIntegerExample { private static AtomicInteger counter = new AtomicInteger(0); public static void main(String[] args) { Runnable task = () -> { for (int i = 0; i < 1000; i++) { counter.incrementAndGet(); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Final counter value: " + counter.get()); } }

现总结一下他的常用方法

构造方法:

  • AtomicInteger():创建一个初始值为 0 的 AtomicInteger 实例。

  • AtomicInteger(int initialValue):创建一个初始值为 initialValue 的 AtomicInteger 实例。

获取和设置值:

  • int get():获取当前值。

  • void set(int newValue):设置新值。

  • int getAndSet(int newValue):获取当前值并设置新值。

原子更新操作:

  • int getAndIncrement():获取当前值并自增 1。

  • int getAndDecrement():获取当前值并自减 1。

  • int getAndAdd(int delta):获取当前值并加上 delta。

  • int incrementAndGet():自增 1 并返回新值。

  • int decrementAndGet():自减 1 并返回新值。

  • int addAndGet(int delta):加上 delta 并返回新值。

这些已经够用了

AtomicInteger类源码中,我们可以看到

java
/* * This class intended to be implemented using VarHandles, but there * are unresolved cyclic startup dependencies. */ private static final Unsafe U = Unsafe.getUnsafe(); public final int incrementAndGet() { return U.getAndAddInt(this, VALUE, 1) + 1; } ....

追溯到Unsafe类

java
// 自旋操作 @IntrinsicCandidate public final int getAndAddInt(Object o, long offset, int delta) { int v; do { v = getIntVolatile(o, offset); } while (!weakCompareAndSetInt(o, offset, v, v + delta)); return v; } @IntrinsicCandidate public final boolean weakCompareAndSetInt(Object o, long offset, int expected, int x) { return compareAndSetInt(o, offset, expected, x); } @IntrinsicCandidate public final native boolean compareAndSetInt(Object o, long offset, int expected, int x);

追溯到这里,后面就是native方法,由cpp实现,使用,除了AtomicInteger,Java还有很多其他的相似类

image.png

下面讲解一下他们的用法,先是AtomicBoolean

常用方法

以下是 AtomicBoolean 类中一些常用的方法:

  • 构造方法

    • AtomicBoolean():创建一个初始值为 falseAtomicBoolean 实例。
    • AtomicBoolean(boolean initialValue):创建一个初始值为 initialValueAtomicBoolean 实例。
  • 获取和设置值

    • boolean get():获取当前值。
    • void set(boolean newValue):设置新值。
    • boolean getAndSet(boolean newValue):获取当前值并设置新值。
  • CAS 操作

    • boolean compareAndSet(boolean expect, boolean update):如果当前值等于 expect,则将其更新为 update,并返回 true;否则返回 false
java
package com.reservoir; import java.util.concurrent.atomic.AtomicBoolean; public class AtomicBooleanExample { private static AtomicBoolean flag = new AtomicBoolean(false); public static void main(String[] args) { // 创建多个线程并发地修改 flag 的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { Boolean b = flag.get(); flag.getAndSet(!b); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的 flag 值 System.out.println("Final flag value: " + flag.get()); } }

AtomicBoolean使用了Java9的VarHandle机制

接下来是AtomicIntegerArray ,提供对整数数组进行原子操作的功能。

常用方法

  • 构造方法

    • AtomicIntegerArray(int length):创建一个给定长度的 AtomicIntegerArray 实例,所有元素初始值为 0。
    • AtomicIntegerArray(int[] array):创建一个 AtomicIntegerArray 实例,元素值从给定的数组中复制。
  • 获取和设置值

    • int get(int i):获取索引 i 处的当前值。
    • void set(int i, int newValue):设置索引 i 处的新值。
    • int getAndSet(int i, int newValue):获取索引 i 处的当前值并设置新值。
  • 原子更新操作

    • int getAndIncrement(int i):获取索引 i 处的当前值并自增 1。
    • int getAndDecrement(int i):获取索引 i 处的当前值并自减 1。
    • int getAndAdd(int i, int delta):获取索引 i 处的当前值并加上 delta
    • int incrementAndGet(int i):自增 1 并返回索引 i 处的新值。
    • int decrementAndGet(int i):自减 1 并返回索引 i 处的新值。
    • int addAndGet(int i, int delta):加上 delta 并返回索引 i 处的新值。
java
import java.util.concurrent.atomic.AtomicIntegerArray; public class AtomicIntegerArrayExample { private static AtomicIntegerArray array = new AtomicIntegerArray(10); public static void main(String[] args) { // 创建多个线程并发地增加数组元素的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { for (int j = 0; j < array.length(); j++) { array.incrementAndGet(j); } } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的数组值 for (int i = 0; i < array.length(); i++) { System.out.println("Array element at index " + i + ": " + array.get(i)); } } }

接下来是AtomicIntegerFieldUpdater 用于提供对指定类的指定 volatile int 字段进行原子操作的功能。

常用方法

以下是 AtomicIntegerFieldUpdater 类中一些常用的方法:

  • 创建 AtomicIntegerFieldUpdater

    • static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName):创建一个 AtomicIntegerFieldUpdater 实例,用于更新指定类的指定 volatile int 字段。
  • 获取和设置值

    • int get(T obj):获取指定对象的指定字段的当前值。
    • void set(T obj, int newValue):设置指定对象的指定字段的新值。
    • int getAndSet(T obj, int newValue):获取指定对象的指定字段的当前值并设置新值。
  • 原子更新操作

    • int getAndIncrement(T obj):获取指定对象的指定字段的当前值并自增 1。
    • int getAndDecrement(T obj):获取指定对象的指定字段的当前值并自减 1。
    • int getAndAdd(T obj, int delta):获取指定对象的指定字段的当前值并加上 delta
    • int incrementAndGet(T obj):自增 1 并返回指定对象的指定字段的新值。
    • int decrementAndGet(T obj):自减 1 并返回指定对象的指定字段的新值。
    • int addAndGet(T obj, int delta):加上 delta 并返回指定对象的指定字段的新值。
java
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; public class AtomicIntegerFieldUpdaterExample { private static class Counter { volatile int count; } private static final AtomicIntegerFieldUpdater<Counter> updater = AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count"); public static void main(String[] args) { Counter counter = new Counter(); // 创建多个线程并发地增加 count 的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { updater.incrementAndGet(counter); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的 count 值 System.out.println("Final count value: " + counter.count); } }

接下来讲解Long相关的原子操作类它们分别是 AtomicLongAtomicLongArrayAtomicLongFieldUpdaterLongAdder

1. AtomicLong

AtomicLong 是 Java 并发包中的一个类,用于提供对 long 类型进行原子操作的功能。它通过无锁算法(基于 CAS 操作)来实现线程安全的原子操作。

常用方法

  • 构造方法

    • AtomicLong():创建一个初始值为 0 的 AtomicLong 实例。
    • AtomicLong(long initialValue):创建一个初始值为 initialValueAtomicLong 实例。
  • 获取和设置值

    • long get():获取当前值。
    • void set(long newValue):设置新值。
    • long getAndSet(long newValue):获取当前值并设置新值。
  • 原子更新操作

    • long getAndIncrement():获取当前值并自增 1。
    • long getAndDecrement():获取当前值并自减 1。
    • long getAndAdd(long delta):获取当前值并加上 delta
    • long incrementAndGet():自增 1 并返回新值。
    • long decrementAndGet():自减 1 并返回新值。
    • long addAndGet(long delta):加上 delta 并返回新值。
java
import java.util.concurrent.atomic.AtomicLong; public class AtomicLongExample { private static AtomicLong counter = new AtomicLong(0); public static void main(String[] args) { // 创建多个线程并发地增加 counter 的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { counter.incrementAndGet(); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的 counter 值 System.out.println("Final counter value: " + counter.get()); } }

2. AtomicLongArray

用于提供对 long 数组进行原子操作的功能。

常用方法

  • 构造方法

    • AtomicLongArray(int length):创建一个给定长度的 AtomicLongArray 实例,所有元素初始值为 0。
    • AtomicLongArray(long[] array):创建一个 AtomicLongArray 实例,元素值从给定的数组中复制。
  • 获取和设置值

    • long get(int i):获取索引 i 处的当前值。
    • void set(int i, long newValue):设置索引 i 处的新值。
    • long getAndSet(int i, long newValue):获取索引 i 处的当前值并设置新值。
  • 原子更新操作

    • long getAndIncrement(int i):获取索引 i 处的当前值并自增 1。
    • long getAndDecrement(int i):获取索引 i 处的当前值并自减 1。
    • long getAndAdd(int i, long delta):获取索引 i 处的当前值并加上 delta
    • long incrementAndGet(int i):自增 1 并返回索引 i 处的新值。
    • long decrementAndGet(int i):自减 1 并返回索引 i 处的新值。
    • long addAndGet(int i, long delta):加上 delta 并返回索引 i 处的新值。
java
import java.util.concurrent.atomic.AtomicLongArray; public class AtomicLongArrayExample { private static AtomicLongArray array = new AtomicLongArray(10); public static void main(String[] args) { // 创建多个线程并发地增加数组元素的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { for (int j = 0; j < array.length(); j++) { array.incrementAndGet(j); } } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的数组值 for (int i = 0; i < array.length(); i++) { System.out.println("Array element at index " + i + ": " + array.get(i)); } } }

3. AtomicLongFieldUpdater

AtomicLongFieldUpdater 用于提供对指定类的指定 volatile long 字段进行原子操作的功能。

常用方法

  • 创建 AtomicLongFieldUpdater

    • static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName):创建一个 AtomicLongFieldUpdater 实例,用于更新指定类的指定 volatile long 字段。
  • 获取和设置值

    • long get(T obj):获取指定对象的指定字段的当前值。
    • void set(T obj, long newValue):设置指定对象的指定字段的新值。
    • long getAndSet(T obj, long newValue):获取指定对象的指定字段的当前值并设置新值。
  • 原子更新操作

    • long getAndIncrement(T obj):获取指定对象的指定字段的当前值并自增 1。
    • long getAndDecrement(T obj):获取指定对象的指定字段的当前值并自减 1。
    • long getAndAdd(T obj, long delta):获取指定对象的指定字段的当前值并加上 delta
    • long incrementAndGet(T obj):自增 1 并返回指定对象的指定字段的新值。
    • long decrementAndGet(T obj):自减 1 并返回指定对象的指定字段的新值。
    • long addAndGet(T obj, long delta):加上 delta 并返回指定对象的指定字段的新值。
java
import java.util.concurrent.atomic.AtomicLongFieldUpdater; public class AtomicLongFieldUpdaterExample { private static class Counter { volatile long count; } private static final AtomicLongFieldUpdater<Counter> updater = AtomicLongFieldUpdater.newUpdater(Counter.class, "count"); public static void main(String[] args) { Counter counter = new Counter(); // 创建多个线程并发地增加 count 的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { updater.incrementAndGet(counter); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的 count 值 System.out.println("Final count value: " + counter.count); } }

4. LongAdder

LongAdder 用于提供对 long 类型进行累加操作的功能,特别适用于高并发场景下的累加操作。基于分段锁

常用方法

  • 构造方法

    • LongAdder():创建一个 LongAdder 实例。
  • 累加操作

    • void add(long x):将指定的值 x 累加到当前值。
    • void increment():将当前值自增 1。
    • void decrement():将当前值自减 1。
  • 获取值

    • long sum():返回当前的总和。
    • void reset():重置总和为 0。
    • long sumThenReset():返回当前的总和,并重置总和为 0。
java
import java.util.concurrent.atomic.LongAdder; public class LongAdderExample { private static LongAdder counter = new LongAdder(); public static void main(String[] args) { // 创建多个线程并发地增加 counter 的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { counter.increment(); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的 counter 值 System.out.println("Final counter value: " + counter.sum()); } }

接下来是引用相关的操作类,有三个与引用类型相关的类,它们分别是 AtomicReferenceAtomicReferenceArrayAtomicReferenceFieldUpdater

1. AtomicReference

AtomicReference 是 Java 并发包中的一个类,用于提供对引用类型进行原子操作的功能。

常用方法

  • 构造方法

    • AtomicReference():创建一个 AtomicReference 实例,初始值为 null
    • AtomicReference(V initialValue):创建一个 AtomicReference 实例,初始值为 initialValue
  • 获取和设置值

    • V get():获取当前值。
    • void set(V newValue):设置新值。
    • V getAndSet(V newValue):获取当前值并设置新值。
java
import java.util.concurrent.atomic.AtomicReference; public class AtomicReferenceExample { private static AtomicReference<String> atomicString = new AtomicReference<>("initial"); public static void main(String[] args) { // 创建多个线程并发地修改 atomicString 的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { String oldValue; String newValue; do { oldValue = atomicString.get(); newValue = oldValue + i; } while (!atomicString.compareAndSet(oldValue, newValue)); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的 atomicString 值 System.out.println("Final atomicString value: " + atomicString.get()); } }

2. AtomicReferenceArray

AtomicReferenceArray 是 Java 并发包中的一个类,用于提供对引用类型数组进行原子操作的功能。

常用方法

  • 构造方法

    • AtomicReferenceArray(int length):创建一个给定长度的 AtomicReferenceArray 实例,所有元素初始值为 null
    • AtomicReferenceArray(E[] array):创建一个 AtomicReferenceArray 实例,元素值从给定的数组中复制。
  • 获取和设置值

    • E get(int i):获取索引 i 处的当前值。
    • void set(int i, E newValue):设置索引 i 处的新值。
    • E getAndSet(int i, E newValue):获取索引 i 处的当前值并设置新值。
java
import java.util.concurrent.atomic.AtomicReferenceArray; public class AtomicReferenceArrayExample { private static AtomicReferenceArray<String> array = new AtomicReferenceArray<>(10); public static void main(String[] args) { // 初始化数组 for (int i = 0; i < array.length(); i++) { array.set(i, "initial"); } // 创建多个线程并发地修改数组元素的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { for (int j = 0; j < array.length(); j++) { String oldValue; String newValue; do { oldValue = array.get(j); newValue = oldValue + i; } while (!array.compareAndSet(j, oldValue, newValue)); } } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的数组值 for (int i = 0; i < array.length(); i++) { System.out.println("Array element at index " + i + ": " + array.get(i)); } } }

3. AtomicReferenceFieldUpdater

AtomicReferenceFieldUpdater 是 Java 并发包中的一个类,用于提供对指定类的指定 volatile 引用字段进行原子操作的功能。

常用方法

  • 创建 AtomicReferenceFieldUpdater

    • static <U, W> AtomicReferenceFieldUpdater<U, W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName):创建一个 AtomicReferenceFieldUpdater 实例,用于更新指定类的指定 volatile 引用字段。
  • 获取和设置值

    • V get(T obj):获取指定对象的指定字段的当前值。
    • void set(T obj, V newValue):设置指定对象的指定字段的新值。
    • V getAndSet(T obj, V newValue):获取指定对象的指定字段的当前值并设置新值。
java
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; public class AtomicReferenceFieldUpdaterExample { private static class Container { volatile String value; } private static final AtomicReferenceFieldUpdater<Container, String> updater = AtomicReferenceFieldUpdater.newUpdater(Container.class, String.class, "value"); public static void main(String[] args) { Container container = new Container(); container.value = "initial"; // 创建多个线程并发地修改 container 的 value 字段的值 Runnable task = () -> { for (int i = 0; i < 1000; i++) { String oldValue; String newValue; do { oldValue = updater.get(container); newValue = oldValue + i; } while (!updater.compareAndSet(container, oldValue, newValue)); } }; Thread thread1 = new Thread(task); Thread thread2 = new Thread(task); thread1.start(); thread2.start(); try { thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } // 输出最终的 value 值 System.out.println("Final value: " + container.value); } }

本文作者:yowayimono

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!