一、字段更新器(P175)
J.U.C 并发包提供了:
AtomicReferenceFieldUpdater // 域 字段
AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
利用字段更新器,可以针对对象的某个域(Field)进行原子操作,只能配合 volatile 修饰的字段使用,否则会出现异常。
@Slf4j(topic = "c.Test40") public class Test40 {public static void main(String[] args) {Student stu = new Student();AtomicReferenceFieldUpdater updater =AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");System.out.println(updater.compareAndSet(stu, null, "张三"));System.out.println(stu);} }class Student {volatile String name;@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +'}';} }
二、原子累加器
1. 累加器性能比较
public class Test41 {public static void main(String[] args) {for (int i = 0; i < 5; i++) {demo(() -> new AtomicLong(0),(adder) -> adder.getAndIncrement());}for (int i = 0; i < 5; i++) {demo(() -> new LongAdder(),adder -> adder.increment());}}/*() -> 结果 提供累加器对象(参数) -> 执行累加操作*/private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {T adder = adderSupplier.get();List<Thread> ts = new ArrayList<>();// 4 个线程,每人累加 50 万for (int i = 0; i < 4; i++) {ts.add(new Thread(() -> {for (int j = 0; j < 500000; j++) {action.accept(adder);}}));}long start = System.nanoTime();ts.forEach(t -> t.start());ts.forEach(t -> {try {t.join();} catch (InterruptedException e) {e.printStackTrace();}});long end = System.nanoTime();System.out.println(adder + " cost:" + (end - start) / 1000_000);} }
性能提升的原因很简单,就是在有竞争的时,设置多个累加单元,Thread - 0 累加 Cell[0],而 Thread - 1 累加 Cell [1] ......最后将结果汇总。这样它们在累加时操作的不同的 Cell 变量,因此减少了 CAS 重试失败,从而提高性能。
2. * 源码之 LongAdder
3. cas 锁(不要用于实现)
@Slf4j(topic = "c.Test42") public class LockCas {// 0 没加锁// 1 加锁private AtomicInteger state = new AtomicInteger(0);public void lock() {while (true) {if (state.compareAndSet(0, 1)) {break;}}}public void unlock() {log.debug("unlock...");state.set(0);}public static void main(String[] args) {LockCas lock = new LockCas();new Thread(() -> {log.debug("begin...");lock.lock();try {log.debug("lock...");sleep(1);} finally {lock.unlock();}}).start();new Thread(() -> {log.debug("begin...");lock.lock();try {log.debug("lock...");} finally {lock.unlock();}}).start();} }
4. * 原理之伪共享
缓存与内存的速度比较
(1)因为 CPU 与 内存的速度差异很大,需要靠预读数据至缓存来提升效率。(2)而缓存以缓存行为单位,每个缓存行对应着一块内存,一般是 64 byte(8 个 long)(3)缓存的加入会造成数据副本的产生,即同一份数据会缓存在不同核心的缓存行中(4)CPU 要保证数据的一致性,如果某个 CPU 核心更改了数据,其它 CPU 核心对应的整个缓存行必须失效
一些源码学习,下次再说吧。。。P177
三、Unsafe
1. 概述
Unsafe 对象提供了非常底层的,操作内存、线程的方法(这些非常的危险),Unsafe 对象不能直接调用,只能通过反射获取。
2. Unsafe CAS 操作
public class TestUnsafe {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");theUnsafe.setAccessible(true);Unsafe unsafe = (Unsafe) theUnsafe.get(null);System.out.println(unsafe);// 1. 获取域的偏移地址long idOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("id"));long nameOffset = unsafe.objectFieldOffset(Teacher.class.getDeclaredField("name"));Teacher t = new Teacher();// 2. 执行 cas 操作unsafe.compareAndSwapInt(t, idOffset, 0, 1);unsafe.compareAndSwapObject(t, nameOffset, null, "张三");// 3. 验证System.out.println(t);} } @Data class Teacher {volatile int id;volatile String name; }
3. 模拟实现原子整数
@Slf4j(topic = "c.Test42") public class Test42 {public static void main(String[] args) {Account.demo(new MyAtomicInteger(10000));} }class MyAtomicInteger implements Account {private volatile int value;private static final long valueOffset;private static final Unsafe UNSAFE;static {UNSAFE = UnsafeAccessor.getUnsafe();// 自定义的方法获取unsafetry {valueOffset = UNSAFE.objectFieldOffset(MyAtomicInteger.class.getDeclaredField("value"));} catch (NoSuchFieldException e) {e.printStackTrace();throw new RuntimeException(e);}}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;}}}public MyAtomicInteger(int value) {this.value = value;}@Overridepublic Integer getBalance() {return getValue();}@Overridepublic void withdraw(Integer amount) {decrement(amount);} }