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操作将失败,不会执行转账。

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

结论

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

相关文章
|
6天前
|
Java 开发者 C++
Java多线程同步大揭秘:synchronized与Lock的终极对决!
【6月更文挑战第20天】在Java多线程编程中,`synchronized`和`Lock`是两种关键的同步机制。`synchronized`作为内置关键字提供基础同步,简单但可能不够灵活;而`Lock`接口自Java 5引入,提供更复杂的控制和优化性能的选项。在低竞争场景下,`synchronized`性能可能更好,但在高并发或需要精细控制时,`Lock`(如`ReentrantLock`)更具优势。选择哪种取决于具体需求和场景,理解两者机制至关重要。
|
6天前
|
Java 测试技术
Java多线程同步实战:从synchronized到Lock的进化之路!
【6月更文挑战第20天】Java多线程同步始于`synchronized`关键字,保证单线程访问共享资源,但为应对复杂场景,`Lock`接口(如`ReentrantLock`)提供了更细粒度控制,包括可重入、公平性及中断等待。通过实战比较两者在高并发下的性能,了解其应用场景。不断学习如`Semaphore`等工具并实践,能提升多线程编程能力。从同步起点到专家之路,每次实战都是进步的阶梯。
|
6天前
|
Java 程序员
从0到1,手把手教你玩转Java多线程同步!
【6月更文挑战第20天】从0到1学Java多线程同步:理解线程同步关键,掌握`synchronized`用法,探索`Lock`接口,实战演练并进阶学习锁升级、`Condition`及死锁预防,成为多线程大师!
|
14天前
|
JavaScript Java 测试技术
《手把手教你》系列技巧篇(七十一)-java+ selenium自动化测试-自定义类解决元素同步问题(详解教程)
【6月更文挑战第12天】本文介绍了如何创建一个自定义类库来解决自动化测试中的元素同步问题。作者指出,大部分错误源于元素因时间不同步而引发,为此提供了一种解决方案。在项目实践中,首先在`library`包下创建名为`MyWait`的类,包含一个方法`isElementPresent`,该方法通过循环尝试并等待指定元素出现,避免了直接使用时间等待可能导致的不准确性。之后,在测试类中调用此自定义方法,成功实现了元素同步。代码示例展示了如何在Java+Selenium自动化测试中应用这个自定义类。
31 2
|
1天前
|
Java 机器人 程序员
如何在Java中进行并发编程:锁与同步机制
如何在Java中进行并发编程:锁与同步机制
|
1天前
|
存储 安全 Java
Java中的线程安全与同步技术
Java中的线程安全与同步技术
|
1天前
|
Java
java线程之信号同步
java线程之信号同步
7 0
|
2天前
|
Java 编译器
Java中4种代码块:普通代码块,静态代码块,同步代码块,构造代码块
Java中4种代码块:普通代码块,静态代码块,同步代码块,构造代码块
|
2天前
|
网络协议 Java
java建立非阻塞TCP链接
java建立非阻塞TCP链接
7 0
|
5天前
|
安全 Java 开发者
Java多线程同步:synchronized与Lock的“爱恨情仇”!
【6月更文挑战第20天】Java多线程中,`synchronized`和`Lock`是线程安全的保障。`synchronized`简单易用,但有局限,如不可中断、无公平策略。`Lock`接口及`ReentrantLock`提供更细粒度控制,支持可中断、公平锁和条件变量,适合复杂场景。在选择时,应根据项目需求权衡简易性和灵活性。示例展示了两者用法差异,强调正确管理锁以避免死锁。理解特点,灵活应用,是多线程编程的关键。