为了避免显示使用synchronized和Lock,在某些场景我们会用cas来避免以上两者的性能开销,cas也叫做原子操作,底层通过计算机底层的cmpxchg指令来实现,cmpxchg介绍如下
cmpxchg
指令的基本格式如下:
assemblycmpxchg destination, source
其中:
destination
是目标操作数,通常是一个内存地址或寄存器。source
是源操作数,通常是一个寄存器。cmpxchg
指令的工作原理如下:
destination
中的值与累加器(通常是 AL
、AX
或 EAX
寄存器,具体取决于操作数的大小)中的值进行比较。destination
中的值等于累加器中的值,则将 source
中的值写入 destination
。ZF
标志位)。以下是一个简单的示例,展示如何在汇编语言中使用 cmpxchg
指令:
assemblysection .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
标志位的状态,程序会跳转到 success
或 failure
标签进行相应的处理。cmpxchg
指令在多线程编程中非常有用,特别是在实现无锁数据结构时。Java 中的 AtomicInteger
类就是基于 CAS 操作实现的,而 CAS 操作通常使用 cmpxchg
指令来实现。
javaimport 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还有很多其他的相似类
下面讲解一下他们的用法,先是AtomicBoolean
以下是 AtomicBoolean
类中一些常用的方法:
构造方法:
AtomicBoolean()
:创建一个初始值为 false
的 AtomicBoolean
实例。AtomicBoolean(boolean initialValue)
:创建一个初始值为 initialValue
的 AtomicBoolean
实例。获取和设置值:
boolean get()
:获取当前值。void set(boolean newValue)
:设置新值。boolean getAndSet(boolean newValue)
:获取当前值并设置新值。CAS 操作:
boolean compareAndSet(boolean expect, boolean update)
:如果当前值等于 expect
,则将其更新为 update
,并返回 true
;否则返回 false
。javapackage 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
处的新值。javaimport 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
并返回指定对象的指定字段的新值。javaimport 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相关的原子操作类它们分别是 AtomicLong
、AtomicLongArray
、AtomicLongFieldUpdater
和 LongAdder
。
AtomicLong
是 Java 并发包中的一个类,用于提供对 long
类型进行原子操作的功能。它通过无锁算法(基于 CAS 操作)来实现线程安全的原子操作。
构造方法:
AtomicLong()
:创建一个初始值为 0 的 AtomicLong
实例。AtomicLong(long initialValue)
:创建一个初始值为 initialValue
的 AtomicLong
实例。获取和设置值:
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
并返回新值。javaimport 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());
}
}
用于提供对 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
处的新值。javaimport 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));
}
}
}
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
并返回指定对象的指定字段的新值。javaimport 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);
}
}
LongAdder
用于提供对 long
类型进行累加操作的功能,特别适用于高并发场景下的累加操作。基于分段锁
构造方法:
LongAdder()
:创建一个 LongAdder
实例。累加操作:
void add(long x)
:将指定的值 x
累加到当前值。void increment()
:将当前值自增 1。void decrement()
:将当前值自减 1。获取值:
long sum()
:返回当前的总和。void reset()
:重置总和为 0。long sumThenReset()
:返回当前的总和,并重置总和为 0。javaimport 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());
}
}
接下来是引用相关的操作类,有三个与引用类型相关的类,它们分别是 AtomicReference
、AtomicReferenceArray
和 AtomicReferenceFieldUpdater
。
AtomicReference
是 Java 并发包中的一个类,用于提供对引用类型进行原子操作的功能。
构造方法:
AtomicReference()
:创建一个 AtomicReference
实例,初始值为 null
。AtomicReference(V initialValue)
:创建一个 AtomicReference
实例,初始值为 initialValue
。获取和设置值:
V get()
:获取当前值。void set(V newValue)
:设置新值。V getAndSet(V newValue)
:获取当前值并设置新值。javaimport 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());
}
}
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
处的当前值并设置新值。javaimport 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));
}
}
}
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)
:获取指定对象的指定字段的当前值并设置新值。javaimport 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 许可协议。转载请注明出处!