当前位置:网站首页>JUC原子引用与ABA问题
JUC原子引用与ABA问题
2022-06-13 09:00:00 【Q z1997】
JUC原子引用
- AtomicReference
- AtomicMarkableReference
- AtomicStampedReference
class DecimalAccountSafeCas implements DecimalAccount {
AtomicReference<BigDecimal> ref;
public DecimalAccountSafeCas(BigDecimal balance) {
ref = new AtomicReference<>(balance);
}
@Override
public BigDecimal getBalance() {
return ref.get();
}
@Override
public void withdraw(BigDecimal amount) {
while (true) {
BigDecimal prev = ref.get();
BigDecimal next = prev.subtract(amount);
if (ref.compareAndSet(prev, next)) {
break;
}
}
}
}
ABA 问题及解决
ABA 问题
static AtomicReference<String> ref = new AtomicReference<>("A");
public static void main(String[] args) throws InterruptedException {
log.debug("main start...");
// 获取值 A
// 这个共享变量被它线程修改过?
String prev = ref.get();
other();
sleep(1);
// 尝试改为 C
log.debug("change A->C {}", ref.compareAndSet(prev, "C"));
}
private static void other() {
new Thread(() -> {
log.debug("change A->B {}", ref.compareAndSet(ref.get(), "B"));
}, "t1").start();
sleep(0.5);
new Thread(() -> {
log.debug("change B->A {}", ref.compareAndSet(ref.get(), "A"));
}, "t2").start();
}
主线程仅能判断出共享变量的值与最初值 A 是否相同,不能感知到这种从 A 改为 B 又 改回 A 的情况,如果主线程希望:
只要有其它线程【动过了】共享变量,那么自己的 cas 就算失败,这时,仅比较值是不够的,需要再加一个版本号
AtomicStampedReference
static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
public static void main(String[] args) throws InterruptedException {
log.debug("main start...");
// 获取值 A
String prev = ref.getReference();
// 获取版本号
int stamp = ref.getStamp();
log.debug("版本 {}", stamp);
// 如果中间有其它线程干扰,发生了 ABA 现象
other();
sleep(1);
// 尝试改为 C
log.debug("change A->C {}", ref.compareAndSet(prev, "C", stamp, stamp + 1));
}
private static void other() {
new Thread(() -> {
log.debug("change A->B {}", ref.compareAndSet(ref.getReference(), "B",
ref.getStamp(), ref.getStamp() + 1));
log.debug("更新版本为 {}", ref.getStamp());
}, "t1").start();
sleep(0.5);
new Thread(() -> {
log.debug("change B->A {}", ref.compareAndSet(ref.getReference(), "A",
ref.getStamp(), ref.getStamp() + 1));
log.debug("更新版本为 {}", ref.getStamp());
}, "t2").start();
}
AtomicStampedReference 可以给原子引用加上版本号,追踪原子引用整个的变化过程,如: A -> B -> A -> C ,通过AtomicStampedReference,我们可以知道,引用变量中途被更改了几次。但是有时候,并不关心引用变量更改了几次,只是单纯的关心是否更改过,所以就有了AtomicMarkableReference

AtomicMarkableReference
class GarbageBag {
String desc;
public GarbageBag(String desc) {
this.desc = desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return super.toString() + " " + desc;
}
}
@Slf4j
public class TestABAAtomicMarkableReference {
public static void main(String[] args) throws InterruptedException {
GarbageBag bag = new GarbageBag("装满了垃圾");
// 参数2 mark 可以看作一个标记,表示垃圾袋满了
AtomicMarkableReference<GarbageBag> ref = new AtomicMarkableReference<>(bag, true);
log.debug("主线程 start...");
GarbageBag prev = ref.getReference();
log.debug(prev.toString());
new Thread(() -> {
log.debug("打扫卫生的线程 start...");
bag.setDesc("空垃圾袋");
while (!ref.compareAndSet(bag, bag, true, false)) {
}
log.debug(bag.toString());
}).start();
Thread.sleep(1000);
log.debug("主线程想换一只新垃圾袋?");
boolean success = ref.compareAndSet(prev, new GarbageBag("空垃圾袋"), true, false);
log.debug("换了么?" + success);
log.debug(ref.getReference().toString());
}
}
边栏推荐
- How to become a white hat hacker? I suggest you start from these stages
- Loss outputs Nan for the Nan model
- Tutorial (5.0) 01 Product introduction and installation * fortiedr * Fortinet network security expert NSE 5
- Redis distributed cluster setup
- 20211115 任意n阶方阵均与三角矩阵(上三角或者下三角)相似
- Web page H5 wechat sharing
- GBase 8a V95与V86压缩策略类比
- 【网络安全】SQL注入新思维之webshell提权
- Bash: kill: (74001) - operation not allowed
- redis
猜你喜欢

Installation of sonarqube code quality management platform (to be continued)

Mapbox usage, including drawing, loading, modifying, deleting points and faces, displaying pop ups, etc

Tutorial (5.0) 03 Security policy * fortiedr * Fortinet network security expert NSE 5

Basic use of cesium, including loading images, terrain, models, vector data, etc
![[security] how to counter attack from 0 to 1 to become a security engineer with zero Foundation](/img/4d/c33a3fcc3b45c2369e1f1f74a8d51b.png)
[security] how to counter attack from 0 to 1 to become a security engineer with zero Foundation

如何成为白帽子黑客?我建议你从这几个阶段开始学习

torch. How to calculate addmm (m, mat1, mat2)

20211104 为什么相似矩阵的迹相同

Qvector shallow copy performance test

消息中间件
随机推荐
Neo4j - CQL使用
Collection of various books
A solution to create a new EXCEL workbook on win10 computer and change the suffix to xlsm (normally it should be xlsx)
Mapbox usage, including drawing, loading, modifying, deleting points and faces, displaying pop ups, etc
Cesium achieves sunny, rainy, foggy, snowy and other effects
關於RSA加密解密原理
Pytorch same structure different parameter name model loading weight
Object array de encapsulation
Implement authentication code login and remember password (cookie)
简单实现数据库链接池
Cesium common events, including click events, mouse events, and camera movement events
Neo4j Environment Building
「解读」华为云桌面说“流畅”的时候,究竟在说什么?
Download address of QT source code of each version
20211115 矩阵对角化的充要条件;满秩矩阵不一定有n个线性无关的特征向量;对称矩阵一定可以对角化
【 sécurité 】 comment devenir ingénieur de sécurité de 0 à 1 contre - attaque pour la Fondation zéro
Map 23 summary
turf. JS usage
Four kinds of hooks in deep learning
【安全】零基礎如何從0到1逆襲成為安全工程師