JAVA高并发-线程安全性(原子性、可见性、有序性)之 原子性

一、原子性

提供了互斥访问,同一时刻只能有一个线程对它进行操作。

保证原子性的操作:

1.Atomic

    1)Atomic:CAS(Unsafe.compareAndSwapInt)

    Atomic包下提供的类利用CAS保证操作的原子性,如和int/integer相对应的AtomicInteger类提供的incrementAndGet()函数实现一个整数自增的操作count++,通过查看源码发现AtomicInteger下的自增操作incrementAndGet(),使用了unsefe的类提供的unsefe.getAndAddInt()方法。unfefe.getAndAddInt()是通过do-while语句做主体函数,其中使用compareAndSwapInt(var1, var2, var5, var5+var4)进行实现。

compareAndSwapInt()方法是一个native方法,代表这是一个java底层的方法。

    该方法的实现原理:

    首先看getAndAddInt()函数的参数列表Object var1是当前传入的对象,var2是当前对象的值,var4是要增加的值(自增:var4为1),方法中var5为获取当前对象在主存中的值;

    然后看compareAndSwapInt()函数的参数列表,var为当前对象,var2为当前传入的值,var5为当前对象在主存中的值,var5+var4是“底层的值” 和 “要增加的值” 的和;

    如果当前对象传入的值var2和底层获取的值var5相等,则将当前对象的值更新为要获取的值也就是var5+var4;否则重新从底层取值var5,重新从var1取值var2,进行判断。通过一直这样循环,保证当我们期望的值和底层的值相同时,才可以操作数据将底层的值刷新为新的值。

compareAndSwap就是CAS的核心,上面介绍的是compareAndSwapInt(),相应的还有compareAndSwapLong()等针对其他类型变量的方法,AtomicBoolean、AtomicLong等针对其他类型变量的类。

    2)LongAdder、AtomicReference、AtomicReferenceFieldUpdater

   (1)jdk8中新增了一个LongAdder类和AtomicLong类非常类似,在Longadder类中将AtomicLong中的incrementAndGet()方法改为了increment()方法。

    为什么新增一个LongAdder类的,是因为在AtomicLong类的CAS算法是在一个死循环内不断尝试修改目标的值,当竞争激烈时修改失败的几率很高也就导致了一直在循环这些原子性操作,性能会受到影响。LongAdder类的核心思想是将数据的热点数据分离。

    比如将AtomicLong的内部核心数据Value分离成一个数组,每个线程访问时通过hash()等算法映射到其中一个元素进行运算,最后的结果为这些运算结果的求和累加,当前value的实际值也有Value分离出的所有元素累计合成。这样做相当与将AtomicLong的单点更新压力分散到各个节点上,在高并发是通过分散提高了性能。

    但LongAdder也有其缺点,当统计时有并发更新可能会导致统计出的数据有误差,比如序列号生成等需要准确且全局唯一数据时,还是应该使用AtomicLong

   (2)原子更新基本类型的AtomicInteger,只能更新一个变量,如果要原子的更新多个变量,就需要使用这个原子更新引用类型提供的类。Atomic包提供了AtomicReference:原子更新引用类型、AtomicReferenceFieldUpdater:原子更新引用类型里的字段。

    AtomicReference

AtomicReferenceFieldUpdater

 3)AtomicStampReference:CAS的ABA问题

    什么是ABA问题:在多线程运行环境下CAS操作时,其他线程将变量A改成了B又改成了A,当本线程用期望值和该变量进行比较时,发现A变量的值没有变就进行了数据修改操作,这样是与设计初衷不符的。

    解决方法是每次变量更新时,会赋给变量一个版本号并加1递增,这样就避免了ABA问题。

     AtomicStampReference类提供了解决这一问题的方法,核心方法是compareAndSet()方法,方法中多了一个对stamp的比较,就是对变量版本号的比较,stamp的值也是在每次变量进行更新时进行维护。

4)AtomicLongArray

    AtomicLongArray中维护的是一个数组,可以选择性的更新其中某一个索引对应的值,是原子性的操作。

    相比于AtomicInteger和AtomicLong中的方法,AtomicLongArray中的方法,参数列表中多了数组索引的值。

    5)AtomicBoolean.compareAndSet()

    这个方法在实际应用中有些场景比较实用,可以实现需要保证“程序只执行一次,绝对不会重复“的场景,它可以保证一个boolean值只被改变一次。

2.原子性-锁(Synchronized)

实现锁的两种方式:

    1)synchronized:在作用对象的作用范围内,依赖JVM实现操作的原子性。

    2)Lock:依赖特殊的CPU指令,代码实现,如ReentrantLock(本章不做说明)。

Synchronized关键字使用方式:

    1)修饰代码块:大括号括起来的代码,作用于调用的对象,也就是当前对象,不同对象之间互不影响,交叉执行。

    2)修饰方法:整个方法,作用于调用的对象,也就是当前对象,不同对象之间互不影响,交叉执行。

    3)修饰静态方法:整个静态方法,作用于所有对象,不同对象调用,不会出现交叉执行的现象。

    4)修饰类:括号括起来的部分,作用于所有对象,不同对象调用,不会出现交叉执行的现象。

注:子类继承父类时,如果父类中有syncronized修饰的方法,syncronized关键字是不会继承过去的,因为syncronized关键字不属于方法声明的一部分。

3.Atomic、Synchronized、Lock对比

syncronized:不可中断锁,适合竞争不激烈场景,可读性好。

Lock:可中断锁,多样化同步,竞争激烈时能维持常态,需要大量代码实现。

Atomic:竞争激烈时能维持常态,比Lock性能好;缺点是一次只能同步一个值,虽然提供了AtomicReference、AtomicReferenceFieldUpdater也只是一次同步一个对象。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容