CAS -> unsafe -> CAS底层思想 -> ABA --> 原子引用更新 --> 如何规避ABA

CAS compareAndSwap 原理

CAS(V,E,N) V表示要更新的变量(内存值)   E表示预期值   N表示新值 (当前值和底层值一样时候,才更新)

传入的值是工作内存,底层的值是主内存,工作内存和主内存不一定是同步的,在某一时间点会同步相同。所以CAS不断尝试,等待他们相同后在操作。

网上的方法实现(理解即可)

public final int getAndAddInt(int delta) {
for (;;) {
int current = get();
int next = current + delta;
if (compareAndSet(current, next))
return next;
}
}
假设delta的值为1,在CAS算法下操作的话,首先进入一个for循环体;假设存在着两个线程,并且内存中的值value=3;根据Java内存模型,每一个线程都存在这这个变量的副本;
    1) 线程1进入循环体,获取到current的值为3,然后获取到到next的值此时为4;此时假设线程1运气不好,被挂起;
    2) 线程2进入循环体,获取到current的值为3,同时next的值也为4;线程2运气好,此时继续执行。 线程2传入两个参数,一个当前值,以及一个预期值;当前值,也就是current=3.要修改成为4;此时当前值也就是预期值和内存中的value比较,此时都是3,那么修改内存中的值为4;
    3)线程1此时再次执行compareAndSwapInt()方法的时候。发现内存中的值为4,预期的值是3,两者不相等,此时就不可以再次赋值
 

CAS的问题

1. 循环时间长开销大: 自旋CAS(不成功,就一直循环执行,直到成功), 并发高的时候耗费CPU.

2. ABA问题  : 如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化。解决思路使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。Java8 AtomicInteger 使用 AtomicStampReference 来解决增加版本号。

3. 只能保证一个共享变量的原子操作

  CAS与Synchronized的使用情景:   

1、对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。

2、对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。

补充: synchronized在jdk1.6之后,已经改进优化。synchronized的底层实现主要依靠Lock-Free的队列,基本思路是自旋后阻塞,竞争切换后继续竞争锁,稍微牺牲了公平性,但获得了高吞吐量。在线程冲突较少的情况下,可以获得和CAS类似的性能;而线程冲突严重的情况下,性能远高于CAS。

Synchronized -  锁 类对象和实例

class Test{
// 以下两个方法是等价的,都是锁住了 new Test()的实例
public void a0() {
synchronized(this) {
}
} public synchronized void a() {
}
}

锁住类

class Test {
// 以下两个方法是等价的
public static void a() {
// 因为是静态方法,共享与不同的线程,所以这里需要锁住整个Test类型,不再是实例
synchronized(Test.class) {
}
} public synchronized static void a() {
}
}

子类不会继承父类的Synchronize方法, 因为Synchronized不属于方法签名。

参考文档

https://www.cnblogs.com/Leo_wl/p/6899716.html

https://blog.csdn.net/tiandao321/article/details/80811103

https://www.cnblogs.com/gosaint/p/9045494.html

https://blog.csdn.net/mmoren/article/details/79185862

CAS和Synchronized的更多相关文章

  1. 【并发编程】【JDK源码】CAS与synchronized

    线程安全 众所周知,Java是多线程的.但是,Java对多线程的支持其实是一把双刃剑.一旦涉及到多个线程操作共享资源的情况时,处理不好就可能产生线程安全问题.线程安全性可能是非常复杂的,在没有充足的同 ...

  2. 并发的核心:CAS 与synchronized, Java8是如何优化 CAS 的?

    大家可能都听说说 Java 中的并发包,如果想要读懂 Java 中的并发包,其核心就是要先读懂 CAS 机制,因为 CAS 可以说是并发包的底层实现原理. 今天就带大家读懂 CAS 是如何保证操作的原 ...

  3. 基础篇:详解锁原理,volatile+cas、synchronized的底层实现

    目录 1 锁的分类 2 synchronized底层原理 3 Object的wait和notify方法原理 4 jvm对synchronized的优化 5 CAS的底层原理 6 CAS同步操作的问题 ...

  4. Java并发(4)- synchronized与CAS

    引言 上一篇文章中我们说过,volatile通过lock指令保证了可见性.有序性以及"部分"原子性.但在大部分并发问题中,都需要保证操作的原子性,volatile并不具有该功能,这 ...

  5. Java并发编程总结2——慎用CAS(转)

    一.CAS和synchronized适用场景 1.对于资源竞争较少的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源:而CAS基于硬件实 ...

  6. 浅析CompareAndSet(CAS)

    最近无意接触了AtomicInteger类compareAndSet(从JDK5开始),搜了搜相关资料,整理了一下 首先要说一下,AtomicInteger类compareAndSet通过原子操作实现 ...

  7. 多线程深入:乐观锁与悲观锁以及乐观锁的一种实现方式-CAS(转)

    原文:https://www.cnblogs.com/qjjazry/p/6581568.html 首先介绍一些乐观锁与悲观锁: 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每 ...

  8. CAS适用场景

    转载:http://www.jb51.net/article/86192.htm 下面小编就为大家带来一篇Java并发编程总结——慎用CAS详解.小编觉得挺不错的, 现在就分享给大家,也给大家做个参考 ...

  9. Java并发问题--乐观锁与悲观锁以及乐观锁的一种实现方式-CAS

    首先介绍一些乐观锁与悲观锁: 悲观锁:总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁.传统的关系型数据库里边就用到了很 ...

随机推荐

  1. Java并发编程原理与实战十四:Lock接口的认识和使用

    保证线程安全演进: synchronized volatile AtomicInteger Lock接口提供的方法: void lock():加锁 void unlock():解锁 void lock ...

  2. markdown里的多层次列表项

    markdown里的多层次列表项 编写python的docstrng太多, 有时候就搞混淆了层次化列表项在博客或者随笔里的规则. docstirng里, 仅用两个空格的缩进就可以实现. 博客里通常是一 ...

  3. Spark1.3.1 On Yarn的集群搭建

    下面给出的是spark集群搭建的环境: 操作系统:最小安装的CentOS 7(下载地址) Yarn对应的hadoop版本号:Hadoop的Cloudera公司发行版Hadoop2.6.0-CDH5.4 ...

  4. UITableView--文档版

    CHENYILONG Blog UITableView Fullscreen   UITableView技术博客http://www.cnblogs.com/ChenYilong/ 新浪微博http: ...

  5. NYOJ 123 士兵杀敌(四) (线段树)

    题目链接 描述 南将军麾下有百万精兵,现已知共有M个士兵,编号为1~M,每次有任务的时候,总会有一批编号连在一起人请战(编号相近的人经常在一块,相互之间比较熟悉),最终他们获得的军功,也将会平分到每个 ...

  6. 假·最大子段和 (sdutoj 4359 首尾相连)(思维)

    题目链接:http://acm.sdut.edu.cn/onlinejudge2/index.php/Home/Contest/contestproblem/cid/2736/pid/4359 具体思 ...

  7. 【算法】Base64编码

    1.说明 Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法. 2.编码 ASCII码 -> 十六进制码 -> ...

  8. mysql5.7半自动同步设置【转】

    mysql的主从复制主要有3种模式: a..主从同步复制:数据完整性好,但是性能消耗高 b.主从异步复制:性能消耗低,但是容易出现主从数据唯一性问题 c.主从半自动复制:介于上面两种之间.既能很好的保 ...

  9. OpenJ_POJ 1058 Guideposts

    Problem OpenJ_POJ Solution 如果我们用 \(G\) 来表示邻接矩阵,那么答案其实就是求\(\sum_{k|i}^n \binom n i G^i\) 为了消除整除的限制,我们 ...

  10. 21 JSON and Go go语言和json

    JSON and Go 25 January 2011 Introduction JSON (JavaScript Object Notation) is a simple data intercha ...