Java的非阻塞同步

简介: Java的非阻塞同步

为什么使用 CAS

随着硬件指令集的发展,我们可以使用基于冲突检测的乐观并发策略: 先进行操作,如果没有其它线程争用共享数据,那操作就成功了,否则采取补偿措施(不断地重试,直到成功为止)。这种乐观的并发策略的许多实现都不需要将线程阻塞,因此这种同步操作称为非阻塞同步。

乐观锁需要操作和冲突检测这两个步骤具备原子性,这里就不能再使用互斥同步来保证了,

因为互斥锁只能防止其他线程进入临界区,但不能防止操作在执行过程中被系统中断或其他硬件事件打断。而硬件支持的原子操作可以保证在整个操作过程中,操作是完全不可分割的,确保了即使在高度并发的环境中也能保持一致性和稳定性。

所以只能靠硬件来完成。硬件支持的原子性操作最典型的是: 比较并交换(Compare-and-Swap,CAS)。CAS 指令需要有 3 个操作数,分别是内存地址 V、旧的预期值 A 和新值 B。当执行操作时,只有当 V 的值等于 A,才将 V 的值更新为 B。


使用场景

示例:银行账户的并发转账

假设有一个简单的在线银行应用,它允许用户在不同账户之间进行资金转账。考虑一个场景,其中两个不同的用户几乎同时从同一个账户A向不同的账户B和C转账。

仅使用互斥同步机制(可能存在问题)
  1. 步骤:
  • 用户1请求从账户A向账户B转移100元。
  • 用户2几乎同时请求从账户A向账户C转移50元。
  1. 互斥同步的实现:
  • 使用互斥锁来确保在任一时刻只有一个转账操作可以访问账户A的余额。
  • 首先,用户1的操作获得锁,开始处理转账。
  • 用户1的操作读取账户A的余额,假设为200元。
  1. 中断和问题:
  • 在用户1的操作完成之前,由于某种原因(例如系统调度、线程切换),该操作被中断。
  • 用户2的操作此时获得锁,开始处理转账。
  • 用户2的操作也读取账户A的余额,仍然是200元(因为用户1的操作尚未完成)。

结果是,两个操作都认为账户A有足够的余额进行转账,可能导致账户A的余额变成负值,这在现实世界是不可接受的。

使用硬件支持的原子操作
  1. 原子操作的实现:
  • 使用像“比较并交换”(Compare and Swap, CAS)这样的硬件支持的原子操作来处理转账。
  • 这样的操作会在一个不可分割的步骤中检查账户余额,并在足够的情况下立即执行转账。
  1. 执行流程:
  • 当用户1的操作尝试进行转账时,CAS指令会检查账户A的余额,并在确认足够后立即扣减100元。
  • 如果用户2的操作几乎同时发生,CAS指令也会尝试执行。
  • 但是,如果账户A的余额不足以支持第二次转账,CAS操作将失败,不会执行转账。

通过这种方式,硬件级的原子操作确保了即使在高度并发的场况下,每次检查和修改账户余额的操作都是不可分割的,从而避免了数据不一致的问题。

结论

这个例子展示了在复杂的并发环境中,仅依靠互斥同步机制可能无法有效地解决所有问题,特别是在需要细粒度控制和高性能的场景下。硬件支持的原子操作提供了一种更加可靠和高效的方式来确保操作的原子性,特别是在涉及共享资源的冲突检测和处理时。

相关文章
|
3月前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
Java多线程同步大揭秘:synchronized与Lock的终极对决!
80 5
|
1月前
|
存储 消息中间件 安全
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
【10月更文挑战第9天】本文介绍了如何利用JUC组件实现Java服务与硬件通过MQTT的同步通信(RRPC)。通过模拟MQTT通信流程,使用`LinkedBlockingQueue`作为消息队列,详细讲解了消息发送、接收及响应的同步处理机制,包括任务超时处理和内存泄漏的预防措施。文中还提供了具体的类设计和方法实现,帮助理解同步通信的内部工作原理。
JUC组件实战:实现RRPC(Java与硬件通过MQTT的同步通信)
|
21天前
|
Java 调度
Java 线程同步的四种方式,最全详解,建议收藏!
本文详细解析了Java线程同步的四种方式:synchronized关键字、ReentrantLock、原子变量和ThreadLocal,通过实例代码和对比分析,帮助你深入理解线程同步机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
Java 线程同步的四种方式,最全详解,建议收藏!
|
26天前
|
安全 Java 开发者
Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用
本文深入解析了Java多线程中的`wait()`、`notify()`和`notifyAll()`方法,探讨了它们在实现线程间通信和同步中的关键作用。通过示例代码展示了如何正确使用这些方法,并分享了最佳实践,帮助开发者避免常见陷阱,提高多线程程序的稳定性和效率。
34 1
|
3月前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
Java多线程同步:synchronized与Lock的“爱恨情仇”!
86 5
|
3月前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
从0到1,手把手教你玩转Java多线程同步!
40 3
|
3月前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
Java多线程同步实战:从synchronized到Lock的进化之路!
101 1
|
3月前
|
开发者 C# 存储
WPF开发者必读:资源字典应用秘籍,轻松实现样式与模板共享,让你的WPF应用更上一层楼!
【8月更文挑战第31天】在WPF开发中,资源字典是一种强大的工具,用于共享样式、模板、图像等资源,提高了应用的可维护性和可扩展性。本文介绍了资源字典的基础知识、创建方法及最佳实践,并通过示例展示了如何在项目中有效利用资源字典,实现资源的重用和动态绑定。
92 0
|
3月前
|
开发者 Java Spring
【绝技揭秘】掌握Vaadin数据绑定:一键同步Java对象,告别手动数据烦恼,轻松玩转Web应用开发!
【8月更文挑战第31天】Vaadin不仅是一个功能丰富的Java Web应用框架,还提供了强大的数据绑定机制,使开发者能轻松连接UI组件与后端Java对象,简化Web应用开发流程。本文通过创建一个简单的用户信息表单示例,详细介绍了如何使用Vaadin的`Binder`类实现数据绑定,包括字段与模型属性的双向绑定及数据验证。通过这个示例,开发者可以更专注于业务逻辑而非繁琐的数据同步工作,提高开发效率和应用可维护性。
84 0
|
3月前
|
Java 开发者
解锁Java并发编程的秘密武器!揭秘AQS,让你的代码从此告别‘锁’事烦恼,多线程同步不再是梦!
【8月更文挑战第25天】AbstractQueuedSynchronizer(AQS)是Java并发包中的核心组件,作为多种同步工具类(如ReentrantLock和CountDownLatch等)的基础。AQS通过维护一个表示同步状态的`state`变量和一个FIFO线程等待队列,提供了一种高效灵活的同步机制。它支持独占式和共享式两种资源访问模式。内部使用CLH锁队列管理等待线程,当线程尝试获取已持有的锁时,会被放入队列并阻塞,直至锁被释放。AQS的巧妙设计极大地丰富了Java并发编程的能力。
44 0