4.1 问题提出
4.1.1 提取款问题
有如下需求,保证account、withdraw取款方法的线程安全。
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
| interface Account { Integer geBalance(); void withdraw(Integer amount);
static void demo(Account account) { List<Thread> ts = new ArrayList<>(); for (int i = 0; i < 1000; i++) { ts.add(new Thread(() -> { account.withdraw(10); })); } long start = System.nanoTime(); ts.forEach(Thread::start); ts.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); ts.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); long end = System.nanoTime(); System.out.printf("final balance: %d, spend time(ms): %d] ", account.geBalance(), (end - start) / 1000_000); } }
|
显然以上做法无法保证线程安全。
4.1.2 锁解决方案
保护共享变量,给临界区加锁。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class AccountSafe implements Account { private Integer balance;
public AccountSafe(Integer balance) { this.balance = balance; }
@Override public Integer geBalance() { return this.balance; }
@Override public void withdraw(Integer amount) { synchronized (this) { this.balance -= amount; } } }
|
4.1.2 无锁解决方案
使用原子整数进行CAS操作:
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
| class AccountCAS implements Account { private AtomicInteger balance;
public AccountCAS(Integer balance) { this.balance = new AtomicInteger(balance); }
@Override public Integer geBalance() { return balance.get(); }
@Override public void withdraw(Integer amount) { while (true) { int prev = this.balance.get(); int next = prev - amount; if (this.balance.compareAndSet(prev, next)) { break; } } } }
|
4.1.3 测试
编写以下代码进行测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class AccountDemo { public static void main(String[] args) { System.out.print("[Unsafe => "); Account a1 = new AccountUnsafe(10000); Account.demo(a1); System.out.print("[synchronized => "); Account a2 = new AccountSafe(10000); Account.demo(a2); System.out.print("[compareAndSet => "); Account a3 = new AccountCAS(10000); Account.demo(a3); System.out.println(); } }
|
测试脚本:
1
| for ($i=0; $i -le 10; $i++) { java top.parak.none.AccountDemo }
|
运行结果:

4.1.5 compareAndSet
compareAndSet,简称CAS(也有Compare And Swap的说法),它必须是原子操作。
1 2 3 4 5 6 7 8 9 10 11
| while (true) { int prev = this.balance.get(); int next = prev - amount; if (this.balance.compareAndSet(prev, next)) { break; } }
|

4.2 CAS与volatile
4.2.1 volatile
获取共享变量时,为了保证该变量的可见性,需要使用volatile修饰。
它可以用来修饰成员变量和静态成员变量,它可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作volatile变量都是操作主存。即一个线程对volatile变量的修改,对另一个线程可见。
CAS必须借助volatile才能读取到共享变量的最新值来实现【比较并交换】的效果。
4.2.2 为什么CAS+重试效率高?
- 在无锁情况下,即使重试失败,线程始终在高速运行,没有停歇,而synchronized会让线程在没有获得锁的时候,发生上下文切换,进入阻塞。
- 但是,在无锁情况下,因为线程要保持运行,需要额外CPU的支持,CPU在这里就好比高速跑道,没有额外的跑道,线程想高速运行也无从谈起,虽然也不会进入阻塞,但由于没有分到时间片,仍然会进入可运行状态,还是会导致上下文切换。
4.2.3 CAS应用场景
结合CAS和volatile可以实现无锁并发,适用于线程数少、多核CPU的场景下:
- CAS是基于乐观锁的思想:非常乐观,假设没有别的线程来修改共享变量,如果其他线程修改了当前线程就再次重试。
- synchronized是基于悲观锁的思想:非常悲观,提防其他线程来修改共享变量,当前线程获取资源就立马上锁,其他争抢资源失败的线程进入阻塞状态,修改结束才开锁,
- CAS体现的是无锁并发、无阻塞并发
- 因为没有使用无锁并发、无阻塞并发,所以线程不会陷入阻塞。
- 但是如果竞争激烈,重试必然 频繁发生,反而效率会收到影响。
4.2.4 CAS特点
优点:
- 可以保证变量操作的原子性
- 并发量低时,CAS效率高于synchronized
- 在线程对共享资源占用时间较短的情况下,使用CAS机制效率也会较高
缺点:
- 无法解决ABA问题
- 可能会消耗较高的CPU
- 不能保证代码块的原子性
4.3 原子整数
JUC提供如下原子整数类:
AtomicBoolean
AtomicInteger
AtomicLong
AtomicInteger
常用API如下:

4.4 原子引用
JUC提供如下原子引用类:
AtomicReference
:普通原子引用类型,对对象进行原子操作
AtomicStampedReference
:带int类型版本戳的原子引用类型,记录更改次数
AtomicMarkableReference
:带boolean类型版本戳的原子引用类型,记录是否更改
作用:保证引用类型的共享变量是线程安全的。
使用BigDemical
实现提取款问题的线程安全解决方案:
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
| class DecimalAccountCAS implements DecimalAccount { private AtomicReference<BigDecimal> balance;
public DecimalAccountCAS(BigDecimal balance) { this.balance = new AtomicReference<>(balance); }
@Override public BigDecimal getBalance() { return balance.get(); }
@Override public void withdraw(BigDecimal amount) { while (true) { BigDecimal prev = balance.get(); BigDecimal next = prev.subtract(amount); if (balance.compareAndSet(prev, next)) { break; } } } }
interface DecimalAccount { BigDecimal getBalance(); void withdraw(BigDecimal amount); }
|
4.4.1 ABA问题
如下程序所示,虽然在other
方法中存在两个线程对共享变量进行了修改,但是经过了两轮修改又变成了原值,main线程对修改共享变量的过程是不可见的,这种操作对业务代码并无影响。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Slf4j(topic = "ABAAtomicReference") public class ABAAtomicReferenceDemo { private static AtomicReference<String> ref = new AtomicReference<>("A");
public static void main(String[] args) throws InterruptedException { log.debug("main start..."); String prev = ref.get(); other(); TimeUnit.SECONDS.sleep(1); log.debug("change A -> K ? {}", ref.compareAndSet(prev, "K")); }
private static void other() { new Thread(() -> log.debug("change A -> B ? {}", ref.compareAndSet(ref.get(), "B")), "B").start(); new Thread(() -> log.debug("change B -> A ? {}", ref.compareAndSet(ref.get(), "A")), "A").start(); } }
|
运行结果:
1 2 3 4
| 2021-04-27 17:29:12.538 [main] DEBUG ABAAtomicReference - main start... 2021-04-27 17:29:12.575 [A] DEBUG ABAAtomicReference - change B -> A ? true 2021-04-27 17:29:12.575 [B] DEBUG ABAAtomicReference - change A -> B ? true 2021-04-27 17:29:13.580 [main] DEBUG ABAAtomicReference - change A -> K ? true
|
虽然ABA对业务没有影响,但是如何让主线程感知到其他线程的修改呢?
4.4.2 AtomicStampedReference
解决ABA问题:
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
| @Slf4j(topic = "ABAAtomicStampedReference") public class ABAAtomicStampedReferenceDemo { private static AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
public static void main(String[] args) throws InterruptedException { log.debug("main start..."); int stamp = ref.getStamp(); other(); TimeUnit.SECONDS.sleep(1); boolean res = ref.compareAndSet(ref.getReference(), "K", stamp, stamp + 1); log.debug("change A -> K ? {}", res); }
private static void other() { new Thread(() -> { int stamp = ref.getStamp(); boolean res = ref.compareAndSet(ref.getReference(), "B", stamp, stamp + 1); log.debug("change A -> B ? {}", res); }).start(); new Thread(() -> { int stamp = ref.getStamp(); boolean res = ref.compareAndSet(ref.getReference(), "A", stamp, stamp + 1); log.debug("change B -> A ? {}", res); }).start(); } }
|
运行结果:
1 2 3 4
| 2021-04-27 18:18:00.754 [main] DEBUG ABAAtomicStampedReference - main start... 2021-04-27 18:18:00.787 [A] DEBUG ABAAtomicStampedReference - change B -> A ? true 2021-04-27 18:18:00.787 [B] DEBUG ABAAtomicStampedReference - change A -> B ? true 2021-04-27 18:18:01.792 [main] DEBUG ABAAtomicStampedReference - change A -> K ? false
|
4.4.3 AtomicMarkableReference
不关心引用变量更改了几次,只是单纯的关心是否更改过。
案例:
家里有清洁机器人和保洁阿姨,垃圾袋满时,需要更换,机器人换了阿姨则不需要换,反之亦然。
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
| @Slf4j(topic = "ABAAtomicMarkableReference") public class ABAAtomicMarkableReferenceDemo { private static GarbageBag bag = new GarbageBag("装满垃圾"); private static AtomicMarkableReference<GarbageBag> ref = new AtomicMarkableReference<>(bag, true);
public static void main(String[] args) throws InterruptedException { log.debug("家里需要换垃圾袋..."); GarbageBag prev = ref.getReference(); robot(); TimeUnit.MILLISECONDS.sleep(10); aunt(); TimeUnit.MILLISECONDS.sleep(10); log.debug(ref.getReference().toString()); }
private static void robot() { new Thread(() -> { log.debug("清洁机器人开始打扫卫生..."); boolean res = ref.compareAndSet(ref.getReference(), new GarbageBag("新垃圾袋"), true, false); log.debug("机器人是否换了垃圾袋 ? {}", res); }, "robot").start(); }
private static void aunt() { new Thread(() -> { log.debug("保洁阿姨开始打扫卫生..."); bag.setDesc("空垃圾袋"); boolean res = ref.compareAndSet(ref.getReference(), new GarbageBag("新垃圾袋"), true, false); log.debug("阿姨是否换了垃圾袋 ? {}", res); }, "aunt").start(); } }
class GarbageBag { String desc;
public GarbageBag(String desc) { this.desc = desc; }
public void setDesc(String desc) { this.desc = desc; }
@Override public String toString() { return "GarbageBag[desc='" + desc + "']"; } }
|
运行结果:
1 2 3 4 5 6
| 2021-04-27 20:01:20.764 [main] DEBUG ABAAtomicMarkableReference - 需要换垃圾袋... 2021-04-27 20:01:20.796 [robot] DEBUG ABAAtomicMarkableReference - 清洁机器人开始打扫卫生... 2021-04-27 20:01:20.796 [robot] DEBUG ABAAtomicMarkableReference - 机器人是否换了垃圾袋 ? true 2021-04-27 20:01:20.809 [aunt] DEBUG ABAAtomicMarkableReference - 保洁阿姨开始打扫卫生... 2021-04-27 20:01:20.809 [aunt] DEBUG ABAAtomicMarkableReference - 阿姨是否换了垃圾袋 ? false 2021-04-27 20:01:20.823 [main] DEBUG ABAAtomicMarkableReference - GarbageBag[desc='新垃圾袋']
|
4.5 原子数组
JUC提供如下原子数组类:
AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
作用:保证数组内的元素的线程安全。
示例:
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
| @Slf4j(topic = "AtomicArray") public class AtomicArrayDemo { public static void main(String[] args) { demo( () -> new int[10], array -> array.length, (array, index) -> array[index]++, array -> log.debug("普通数组:{}", Arrays.toString(array)) ); demo( () -> new AtomicIntegerArray(10), AtomicIntegerArray::length, AtomicIntegerArray::getAndIncrement, array -> log.debug("安全数组:{}", array) ); }
private static <T> void demo(Supplier<T> arraySupplier, Function<T, Integer> lengthFunction, BiConsumer<T, Integer> putConsumer, Consumer<T> printConsumer) { List<Thread> list = new ArrayList<>(); T array = arraySupplier.get(); int length = lengthFunction.apply(array);
for (int i = 0; i < length; i++) { list.add(new Thread(() -> { for (int j = 0; j < 10000; j++) { putConsumer.accept(array, j % length); } })); }
list.forEach(Thread::start); list.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); printConsumer.accept(array); } }
|
运行结果:
1 2
| 2021-04-27 21:09:01.160 [main] DEBUG AtomicArray - 普通数组:[6531, 6533, 6501, 6566, 6515, 6508, 6499, 6519, 6489, 6527] 2021-04-27 21:09:01.166 [main] DEBUG AtomicArray - 安全数组:[10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000, 10000]
|
4.6 字段更新器
JUC提供如下字段更新器:
AtomicReferenceFeildUpdater
:引用类型的属性
AtomicIntegerFieldUpdater
:整形的属性
AtomicLongFeildUpdater
:长整形的属性
注意:利用字段更新器,可以针对对象的某个域(Field)进行原子操作,只能配合volatile修饰的字段使用,否则会出现异常。
1
| Exception in thread "main" java.lang.IllegalArgumentException: Must be volatile type
|
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Slf4j(topic = "AtomicFieldUpdater") public class AtomicFieldUpdaterDemo { public static void main(String[] args) { Student stu = new Student(); AtomicReferenceFieldUpdater updater = AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name"); log.debug("update ? {}", updater.compareAndSet(stu, null, "RubbishK")); log.debug("update ? {}", updater.compareAndSet(stu, stu.getName(), "FlowerK")); log.debug(stu.toString()); } }
class Student { volatile String name;
public String getName() { return name; }
@Override public String toString() { return "Student[name='" + name + "']"; } }
|
运行结果:
1 2 3
| 2021-04-27 21:36:51.784 [main] DEBUG AtomicFieldUpdater - update ? true 2021-04-27 21:36:51.786 [main] DEBUG AtomicFieldUpdater - update ? true 2021-04-27 21:36:51.786 [main] DEBUG AtomicFieldUpdater - Student[name='FlowerK']
|
4.7 原子累加器
JUC提供如下原子累加器:
LongAddr
LongAccumulator
DouleAddr
DoubleAccumulator
4.7.1 累加性能比较
累加性能比较AtomicLong
,LongAddr
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
| @Slf4j(topic = "Compare") public class PerformanceCompareDemo { public static void main(String[] args) { for (int i = 0; i < 5; i++) { demo(AtomicLong::new, AtomicLong::getAndIncrement); } for (int i = 0; i < 5; i++) { demo(LongAdder::new, LongAdder::increment); } }
private static <T> void demo(Supplier<T> supplier, Consumer<T> consumer) { T adder = supplier.get(); long start = System.nanoTime(); List<Thread> list = new ArrayList<>(); for (int i = 0; i < 40; i++) { list.add(new Thread(() -> { for (int k = 0; k < 50_0000; k++) { consumer.accept(adder); } })); } list.forEach(Thread::start); list.forEach(t -> { try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } }); long end = System.nanoTime(); log.debug("{} cost: {}(ns)", adder.getClass().getSimpleName(), (end - start)); } }
|
运行结果:
1 2 3 4 5 6 7 8 9 10
| 2021-04-27 22:34:29.842 [main] DEBUG Compare - AtomicLong cost: 363865900(ns) 2021-04-27 22:34:30.176 [main] DEBUG Compare - AtomicLong cost: 331326300(ns) 2021-04-27 22:34:30.565 [main] DEBUG Compare - AtomicLong cost: 388361700(ns) 2021-04-27 22:34:30.961 [main] DEBUG Compare - AtomicLong cost: 396090500(ns) 2021-04-27 22:34:31.349 [main] DEBUG Compare - AtomicLong cost: 386800900(ns) 2021-04-27 22:34:31.404 [main] DEBUG Compare - LongAdder cost: 53539000(ns) 2021-04-27 22:34:31.438 [main] DEBUG Compare - LongAdder cost: 33946400(ns) 2021-04-27 22:34:31.479 [main] DEBUG Compare - LongAdder cost: 40203000(ns) 2021-04-27 22:34:31.511 [main] DEBUG Compare - LongAdder cost: 32314300(ns) 2021-04-27 22:34:31.546 [main] DEBUG Compare - LongAdder cost: 34245400(ns)
|
可以发现,LongAddr
的速度要比AtomicLong
高出一个数量级。
4.7.2 LongAdder源码分析
先贴一下前辈的主页:http://gee.cs.oswego.edu
作为并发大师@Doug lea 的作品LongAdder
,它的设计非常精巧。
LongAdder
类有几个关键域:
1 2 3 4 5 6 7 8
| transient volatile Cell[] cells;
transient volatile long base;
transient volatile int cellsBusy;
|
4.7.2.1 CAS锁
切勿使用生产环境。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Slf4j(topic = "LockCAS") public class LockCASDemo { // 0表示没加锁 // 1表示加了锁 private final AtomicInteger state = new AtomicInteger(0);
private void lock() { while (true) { if (state.compareAndSet(0, 1)) { break; } } }
public void unlock() { log.debug("unlock..."); state.set(0); } }
|
4.7.2.1 原理之伪共享
Cell即为累加单元。
1 2 3 4 5 6 7 8 9 10 11 12
| @Sun.misc.Contented static final class Cell { volatile long value; Cell(long x) { value = x; } final boolean cas(long prev, long next) { return UNSAFE.compareAndSwapLong(this, valueOffset, prev, next); } }
|
从缓存说起,缓存与内存的速度比较:

从CPU到 |
大约需要的时钟周期 |
寄存器 |
1 cycle(4GHz的CPU约为0.25ns) |
L1 |
3~4 cycle |
L2 |
10~20 cycle |
L3 |
40~45 cycle |
内存 |
120~240 cycle |
因为CPU与内存的速度差异很大,需要靠预读数据至缓存来提升效率。
而缓存以缓存行为单位,每个缓存对应着一块内存,一般是64 byte(8个long)。
缓存的加入会造成数据副本的产生,即同一份数据会缓存在不同核心的缓存行中。
CPU要保证数据的一致性,如果某个CPU核心更改了数据,其他CPU核心对应的整个缓存行必须失效。

因为Cell是数组形式,在内存中是连续存储的,一个Cell为24字节(16字节的对象头和8字节的value),因此缓存行可以存下2个的Cell对象。这样问题来了;
- Core-0要修改Cell[0]
- Core-1要修改Cell[1]
无论谁修改成功,都会导致对方Core的缓存行失效,比如Core-0中Cell[0] = 6000,Cell[1] = 8000。要累加Cell[0] = 6001,Cell[1] = 8000,这时会让Core-1缓存行失效。
@sun.misc.Contented
用来解决这个问题,它的原理是在使用此注解的对象或字段的前后各增加128字节大小的padding,从而让CPU将对象预读至缓存时占用不同的缓存行,这样,不会造成对方缓存行的失效。

4.7.2.2 主要方法
add
方法:
1 2 3 4 5 6 7 8 9 10 11
| public void add(long x) { Cell[] as; long b, v; int m; Cell a; if ((as = cells) != null || !casBase(b = base, b + x) ) { boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = a.cas(v = a.value, v + x))) longAccumulate(x, null, uncontended); } }
|

longAccumulate
方法:
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 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| final void longAccumulate(long x, LongBinaryOperator fn, boolean wasUncontended) { int h; if ((h = getProbe()) == 0) { ThreadLocalRandom.current(); h = getProbe(); wasUncontended = true; } boolean collide = false; for (;;) { Cell[] as; Cell a; int n; long v; if ((as = cells) != null && (n = as.length) > 0) { if ((a = as[(n - 1) & h]) == null) { if (cellsBusy == 0) { Cell r = new Cell(x); if (cellsBusy == 0 && casCellsBusy()) { boolean created = false; try { Cell[] rs; int m, j; if ((rs = cells) != null && (m = rs.length) > 0 && rs[j = (m - 1) & h] == null) { rs[j] = r; created = true; } } finally { cellsBusy = 0; } if (created) break; continue; } } collide = false; } else if (!wasUncontended) wasUncontended = true; else if (a.cas(v = a.value, ((fn == null) ? v + x : fn.applyAsLong(v, x)))) break; else if (n >= NCPU || cells != as) collide = false; else if (!collide) collide = true; else if (cellsBusy == 0 && casCellsBusy()) { try { if (cells == as) { Cell[] rs = new Cell[n << 1]; for (int i = 0; i < n; ++i) rs[i] = as[i]; cells = rs; } } finally { cellsBusy = 0; } collide = false; continue; } h = advanceProbe(h); } else if (cellsBusy == 0 && cells == as && casCellsBusy()) { boolean init = false; try { if (cells == as) { Cell[] rs = new Cell[2]; rs[h & 1] = new Cell(x); cells = rs; init = true; } } finally { cellsBusy = 0; } if (init) break; } else if (casBase(v = base, ((fn == null) ? v + x : fn.applyAsLong(v, x)))) break; } }
|



sum
方法:
1 2 3 4 5 6 7 8 9 10 11
| public long sum() { Cell[] as = cells; Cell a; long sum = base; if (as != null) { for (int i = 0; i < as.length; ++i) { if ((a = as[i]) != null) sum += a.value; } } return sum; }
|
4.8 Unsafe
4.8.1 概述
Unsafe
对象提供了非常底层的,操作内存、线程的办法,Unsafe
对象不能直接调用,只能通过反射获得:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class UnsafeAccessor { private static Unsafe unsafe;
static { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); unsafe = (Unsafe) theUnsafe.get(null); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } }
static Unsafe getUnsafe() { return unsafe; } }
|
4.8.2 CAS操作
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
| public class UnsafeDemo { public static void main(String[] args) throws NoSuchFieldException { Unsafe unsafe = UnsafeAccessor.getUnsafe(); Field id = User.class.getDeclaredField("id"); Field name = User.class.getDeclaredField("name"); long idOffset = unsafe.objectFieldOffset(id); long nameOffset = unsafe.objectFieldOffset(name); User user = new User(); unsafe.compareAndSwapInt(user, idOffset, 0, 1); unsafe.compareAndSwapObject(user, nameOffset, null, "KHighness"); System.out.println(user); } }
class User { volatile int id; volatile String name;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
@Override public String toString() { return "User[" + "id=" + id + ", name='" + name + '\'' + ']'; } }
|
运行结果:
1
| User[id=1, name='KHighness']
|
4.8.3 自定义原子实现类
使用自定义的AtomicData
实现之前线程安全的原子整数Account
实现:
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
| class KAtomicInteger implements Account{ private volatile int value; private static long valueOffset; private static final Unsafe UNSAFE;
static { UNSAFE = UnsafeAccessor.getUnsafe(); try { valueOffset = UNSAFE.objectFieldOffset(KAtomicInteger.class.getDeclaredField("value")); } catch (NoSuchFieldException e) { e.printStackTrace(); } }
public KAtomicInteger(int value) { this.value = value; }
public int getValue() { return value; }
public void decrement(int amount) { while (true) { int prev = this.value; int next = prev - amount; if (UNSAFE.compareAndSwapInt(this, valueOffset, prev, next)) { break; } } }
@Override public Integer geBalance() { return getValue(); }
@Override public void withdraw(Integer amount) { decrement(amount); } }
|