问题描述
因为原子表示线程安全.当.set()本身是Atomic并且在Java中是线程安全的时,我们何时使用compareAndSet?
Since Atomic means thread safe. When do we ever use compareAndSet when .set() itself is Atomic and thread safe in java?
例如,我想原子地设置一个变量,以便其他所有线程都可以看到它(但是我希望以线程安全的方式设置该变量),我可以简单地将其声明为volatile AtomicBoolean或volatile AtomicInteger,这应该好吧?在什么情况下需要使用compareAndSet?
say for example I want to set a variable atomically such that every other thread can see it (but I want the variable to be set in a thread safe manner) I could simple declare it as volatile AtomicBoolean or volatile AtomicInteger and that should be good right? what are some of cases where I need to use compareAndSet?
推荐答案
在多线程环境中有两个重要的概念.
There are two important concepts in multithreading environment.
- 原子性
- 可见度
Volatile
解决了可见性问题,但不处理原子性,例如我++.在这里,i ++不是单条机器指令,而是三条机器指令.
Volatile
solves the visibility problem but it does not deal with atomicity e.g. i++. Here i++ is not a single machine instruction rather it is three machine instructions.
- 复制值进行注册
- 增加它
- 放回去
AtomicInteger
,AtomicReference
基于比较和交换指令. CAS具有三个要在其上进行操作的存储位置V,预期的旧值A和新值B的操作数.否则它什么都不做.无论哪种情况,它都返回当前以V表示的值.JVM在AtomicInteger
,AtomicReference
中使用该值,并且如果基础处理器不支持此功能,则它们将函数称为compareAndSet()
,然后JVM通过自旋锁实现该功能. .
AtomicInteger
, AtomicReference
are based on the Compare and swap instruction. CAS has three operands a memory location V on which to operate, the expected old value A, and the new value B. CAS atomically updates V to the new value B, but only if the value in V matches the expected old value A; otherwise it does nothing. In either case, it returns the value currently in V. This is used by JVM in AtomicInteger
, AtomicReference
and they call the function as compareAndSet()
if this functionality is not supported by underlying processor then JVM implements it by spin lock.
Set是原子的(它并不总是正确的),但是比较然后set不是原子的.因此,如果您对此 有要求,例如当值是X时,仅更改为Y,因此要进行原子操作,您需要这种基元 .您可以使用AtomicInteger
,AtomicReference
的compareAndSet例如atomicLong.compareAndSet(long expect, long update)
Set is atomic (it is not always correct) but compare and then set is not atomic. So when you have a requirement for this e.g. when the value is X then only change to Y so to do this atomically you need this kind of primitives you can use compareAndSet of AtomicInteger
, AtomicReference
e.g. atomicLong.compareAndSet(long expect, long update)
您实际上可以使用此原语来开发功能强大的数据结构,例如并发堆栈.
You can actually use this primitives to develop powerful datastrucutures like Concurrent stack.
import java.util.concurrent.atomic.AtomicReference;
public class MyConcurrentStack<T> {
private AtomicReference<Node> head = new AtomicReference<Node>();
public MyConcurrentStack() {
}
public void push(T t) {
if (t == null) {
return;
}
Node<T> n = new Node<T>(t);
Node<T> current;
do {
current = head.get();
n.setNext(current);
} while (!head.compareAndSet(current, n));
}
public T pop() {
Node<T> currentHead = null;
Node<T> futureHead = null;
do {
currentHead = head.get();
if (currentHead == null) {
return null;
}
futureHead = currentHead.next;
} while (!head.compareAndSet(currentHead, futureHead));
return currentHead.data;
}
/**
*
* @return null if no element present else return a element. it does not
* remove the element from the stack.
*/
public T peek() {
Node<T> n = head.get();
if (n == null) {
return null;
} else {
return n.data;
}
}
public boolean isEmpty() {
if (head.get() == null) {
return true;
}
return false;
}
private static class Node<T> {
private final T data;
private Node<T> next;
private Node(T data) {
this.data = data;
}
private void setNext(Node next) {
this.next = next;
}
}
}
这篇关于当set在Java中已经是原子时,为什么我们需要compareAndSet?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!