link
Q: AtomicInteger底层原理?什么是CAS, 怎么使用CAS?
Atomic*
- AtomicInteger对int类型的封装,提供原子性的读取和更新操作
1 | // 不能保证原子性 |
- 底层用的CAS技术实现
Compare the value of the primitive to the value we have got in hand. 对比已有的值
If the values do not match it means some thread in between has changed the value. Else it will go ahead and swap the value with new value. 如果不匹配说明有其他线程修改了这个值然后返回,否则交换新的值
1 | // jdk8 之前 |
LongAdder
替代AtomicLong的方案
When no contention is present AtomicLong performs better
This class is usually preferable to AtomicLong when multiple threads update a common sum that is used for purposes such as collecting statistics, not for fine-grained synchronization control
LongAdder will allocate Cells (a final class declared in abstract class Striped64) to avoid contention which consumes memory. So in case we have a tight memory budget we should prefer AtomicLong
CAS原理
There are 3 parameters for a CAS operation:
1、A memory location V where value has to be replaced
2、Old value A which was read by thread last time
3、New value B which should be written over VCAS says “I think V should have the value A; if it does, put B there, otherwise don’t change it but tell me I was wrong.” CAS is an optimistic technique—it proceeds with the update in the hope of success, and can detect failure if another thread has updated the variable since it was last examined.
1 | public final int getAndIncrement() { |
CAS使用
- Atomic*FieldUpdater
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61public class CASDemo {
private static final AtomicLongFieldUpdater<CASDemo> UPDATER = AtomicLongFieldUpdater.newUpdater(CASDemo.class, "lock");
private volatile long lock;
public void acquireLock() {
Long id = Thread.currentThread().getId();
System.out.println(String.format("线程%s进入获取锁", id));
while (!UPDATER.compareAndSet(this, 0L, id)) {
}
System.out.println(String.format("线程%s获取锁", id));
}
public void releaseLock() {
Long id = Thread.currentThread().getId();
System.out.println(String.format("线程%s进入释放锁", id));
while (!UPDATER.compareAndSet(this, id, 0L)) {
}
System.out.println(String.format("线程%s释放锁", id));
}
public static void main(String[] args) {
CASDemo demo = new CASDemo();
Runnable runnable = () -> {
demo.acquireLock();
for (int i = 0; i < 3; i++) {
System.out.println(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
demo.releaseLock();
};
new Thread(runnable).start();
new Thread(runnable).start();
}
}
// 不使用acquireLock、releaseLock的输出结果
0
0
1
1
2
2
// 使用acquireLock、releaseLock的输出结果
线程11进入获取锁
线程12进入获取锁
线程11获取锁
0
1
2
线程11进入释放锁
线程11释放锁
线程12获取锁
0
1
2
线程12进入释放锁
线程12释放锁
lock-free机制
ABA 问题