java并发之非阻塞同步

北慕城南 提交于 2020-01-07 03:30:23

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

阻塞同步最大的问题是线程阻塞和唤醒带来的性能问题(用户态,内核态的切换),从处理问题的方式来说,阻塞同步属于悲观的并发策略,总是认为只要不去做正确的同步措施,那就肯定会出问题,无论共享数据是否对会出现竞争,它都要加锁。

随着硬件指令集的发展,有了另一种选择:基于冲突检测的乐观并发策略,通俗的讲,就是先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据有争用,产生了冲突,那就采取补偿措施(而不是线程阻塞,挂起,该线程仍然持有cpu分配的时间)最常见的补偿措施就是不断重试,直到成功为止,这种方式叫做:乐观并发策略。

乐观并发策略需要操作和冲突检测这两个步骤具备原子性,所以硬件指令集的发展,让硬件保证一个从语义上看起来需要多次操作的行为只通过一条处理器指令就能完成,这类指令常用的用:

  • 测试并设置(Test-and-Set)。
  • 获取并增加(Fech-and-Increment)。
  • 交换(Swap)
  • 比较并交换(Compare-and-Swap:CAS)。
  • 加载链接/条件存储(Load-Linked/Store-Conditional:LL/SC)

JDK1.5之后,Java程序中可以使用CAS操作,该操作由sun.misc.Unsafe类里面的compareAndSwapInt()和compareAndSwapLong()等几个方法保证提供,虚拟机在内部对这些方法做了特殊处理,即使编译出来的结果就是一条平台相关的处理器CAS指令。

CAS指令需要有3个操作数,分别是:

  1. 内存位置(理解为变量的内存地址,用V表示)
  2. 旧的预期值(用A表示)
  3. 新值(用B表示)

 

CAS指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则它就不执行更新,但是无论是否更新了V的值,都会返回V的旧值,上述的过程就是一个原子操作。

 

 

CAS技术参考文章:https://www.cnblogs.com/ldws/p/11970087.html

 

jdk的J.U.C包下的各种Atomic类就是使用CAS技术实现的。

 

CAS也有不完美的问题,存在一个逻辑漏洞:ABA问题。

如果一个变量初始读取的时候是A值

并且在准备赋值的时候检查到它仍然是A值

那我们就能说它的值没有被其他线程该过吗?

 

如果在这段期间它的值曾经被改成了B,后台有被改成了A,那CAS操作就会误认为它从来没有被改变过。这个漏洞称为CAS操作的“ABA”问题。大部分情况下ABA问题不会影响程序并发的正确性。

ABA问题参考:https://www.cnblogs.com/moris5013/p/11824993.html

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!