(十三) 共享模型之无锁【字段更新器、原子累加器、Unsafe】

news/2024/11/28 3:31:51/

一、字段更新器(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 byte8 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);}
}


http://www.ppmy.cn/news/1708.html

相关文章

计算机毕业设计Java基本web蓝桥杯名师工作室(源码+系统+mysql数据库+lw文档)

计算机毕业设计Java基本web蓝桥杯名师工作室(源码系统mysql数据库lw文档) 计算机毕业设计Java基本web蓝桥杯名师工作室(源码系统mysql数据库lw文档)本源码技术栈&#xff1a; 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 开发软件&#xff1a;idea eclipse …

[附源码]Python计算机毕业设计SSM竞赛报名管理系统(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

用html做一个漂亮的网站【茶文化12页】期末网页制作 HTML+CSS网页设计实例 企业文化网站制作

&#x1f389;精彩专栏推荐 &#x1f4ad;文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 &#x1f482; 作者主页: 【主页——&#x1f680;获取更多优质源码】 &#x1f393; web前端期末大作业&#xff1a; 【&#x1f4da;毕设项目精品实战案例 (10…

Python中的全局变量与命名法

--------------------------------------------------------------------------------------------------------------------------------- 在本文章中&#xff0c;我们来讨论一下python中的全局变量&#xff0c;我们将学习如何定义全局变量&#xff0c;然后如何在函数中访问它…

多线程初阶(二)

目录 前言&#xff1a; synchronized 解析 可重入和不可重入问题 解析 Java中线程安全类 死锁问题 解析 解决死锁问题 解析 内存可见性 解析 volatile关键字 解析 wait&#xff0c;notify 解析 小结&#xff1a; 前言&#xff1a; 针对上篇文章讲到的线程安全…

【数据结构】二分搜索树

目录 一、二分搜索树 1.1什么是二分搜索树 1.2创建一个二分搜索树 &#xff08;1&#xff09;二分搜索树的内部构建 &#xff08;2&#xff09;插入操作 &#xff08;3&#xff09;判断一个val值是否存在 &#xff08;4&#xff09;按照节点的深度先序遍历打印BST &#…

【深度梯度投影网络:遥感图像】

Deep Gradient Projection Networks for Pan-sharpening &#xff08;用于全色锐化的深度梯度投影网络&#xff09; 全色锐化是遥感成像系统获取高分辨率多光谱图像的重要技术。最近&#xff0c;深度学习已经成为最流行的泛锐化工具。提出了一种基于模型的深度全色锐化方法。…

计算机毕业设计Java机票实时比价系统(源码+系统+mysql数据库+lw文档)

计算机毕业设计Java机票实时比价系统(源码系统mysql数据库lw文档) 计算机毕业设计Java机票实时比价系统(源码系统mysql数据库lw文档)本源码技术栈&#xff1a; 项目架构&#xff1a;B/S架构 开发语言&#xff1a;Java语言 开发软件&#xff1a;idea eclipse 前端技术&#…