线程安全性

当多线程访问某个类时,不管运行环境采用何种调度方式或者这些进程将如何交替执行,并且在主调代码中不需要任何的同步或者协同,这个类都能表现出正确的行为,那么这个类就是线程安全的.

原子性

提供互斥访问,同一时刻只有一个线程对它进行访问.

Atomic包

位于java.util.concurrent.atomic,AtomicXXX : CAS、Unsafe.compareAndSwapXXX

CAS(Compare and swap)比较和替换是设计并发算法用的的一项技术,比较和替换是用一个期望值和一个变量的当前值进行比较,如果变量的值和期望值相等,那么就用一个新值替换变量的值.

案例

线程安全

package com.keytech.task;import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;/*** @className: AtomicTest* @description: TODO 类描述* @author: mac* @date: 2020/12/27**/
public class AtomicTest {private static Integer clientTotal=5000;private static Integer threadTotal=200;private static AtomicInteger count=new AtomicInteger(0);public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();Semaphore semaphore= new Semaphore(threadTotal);for (int i = 0; i <clientTotal ; i++) {executorService.execute(()->{try{semaphore.acquire();update();semaphore.release();}catch (Exception e){e.printStackTrace();}});}executorService.shutdown();System.out.println("count:"+count);}private static void update(){count.incrementAndGet();}
}

getAndAddInt源码

public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;
}

compareAndSwapInt(this, stateOffset, expect, update)这个方法的作用就是通过cas技术来预测stateOffset变量的初始值是否是expect,如果是,那么就把stateOffset变量的值变成update,如果不是,那么就一直自旋转,一直到stateOffset变量的初始值是expect,然后在在修改stateOffset变量的值变成update

LongAddr

线程安全

package com.keytech.task;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.LongAdder;/*** @className: LongAddrTest* @description: TODO 类描述* @author: mac* @date: 2020/12/28**/
public class LongAddrTest {private static Integer clientTotal=5000;private static Integer threadTotal=200;private static LongAdder count=new LongAdder();public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();Semaphore semaphore=new Semaphore(threadTotal);for (int i = 0; i < clientTotal; i++) {try{semaphore.acquire();update();semaphore.release();}catch (Exception e){e.printStackTrace();}}executorService.shutdown();System.out.println("count"+count);}private static void update(){count.increment();}
}

AtomicLong

线程安全

package com.keytech.task;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicLong;/*** @className: AtomicLongTest* @description: TODO 类描述* @author: mac* @date: 2020/12/28**/
public class AtomicLongTest {private static Integer clientTotal=5000;private static Integer threadTotal=200;private static AtomicLong count=new AtomicLong();public static void main(String[] args) {ExecutorService executorService = Executors.newCachedThreadPool();Semaphore semaphore=new Semaphore(threadTotal);for (int i = 0; i < clientTotal; i++) {try{semaphore.tryAcquire();update();semaphore.release();}catch (Exception e){e.printStackTrace();}}executorService.shutdown();System.out.println("count"+count);}private static void update(){count.incrementAndGet();}
}

LongAddr与AtomicLong的区别

AtomicLong的原理是依靠底层的cas来保障原子性的更新数据,在要添加或者减少的时候,会使用死循环不断地cas到特定的值,从而达到更新数据的目的。如果竞争不激烈,修改成功几率很高,否则失败概率很高,在失败几率很高的情况下,这些原子操作就会进行多次的循环操作尝试,因此性能会受到影响。

对于普通类型的Long和Doubble变量,JVM允许将64位的读操作或写操作拆成两个三十二位的操作。

LongAdder则是内部维护一个Cells数组,每个Cell里面有一个初始值为0的long型变量,在同等并发量的情况下,争夺单个变量的线程会减少,这是变相的减少了争夺共享资源的并发量,另外多个线程在争夺同一个原子变量时候,如果失败并不是自旋CAS重试,而是尝试获取其他原子变量的锁,最后当获取当前值时候是把所有变量的值累加后再加上base的值返回的。

LongAdder的核心是将热点数据分离,比如说它可以将AtomicLong内部核心数据value分离成一个数组,每个线程访问时,通过hash等算法,映射到其中一个数字进行计数,最终的计数结果则会这个数据的求和累加,其中热点数据value会被分离成多个cell,每个cell独自维护内部的值,当前对象实际值为所有cell累计合成,这样的话,热点就进行了有效的分离,并提高了并行度。

LongAdder在AtomicLong的基础上将单点的更新压力分散到各个节点,在低并发的时候通过对base的直接更新可以很好的保障和AtomicLong的性能基本保持一致,而在高并发的时候通过分散提高了性能。缺点是LongAdder在统计的时候如果有并发更新,可能导致统计的数据有误差。

LongAddr与AtomicLong的使用场景

实际使用中,在处理高并发时,可以优先使用LongAdder,而不是继续使用AtomicLong,当然,在线程竞争很低的情况下,使用AtomicLong更简单更实际一些,并且效率会高些。其他情况下,比如序列号生成,这种情况下需要准确的数值,全局唯一的AtomicLong才是正确的选择,而不是LongAdder

线程安全之原子性Atomic(AtomicInteger|LongAdder|AtomicLong)相关推荐

  1. java 线程安全Long_【Java】线程安全之原子性Atomic(AtomicInteger|LongAdder|AtomicLong)

    线程安全性 原子性 Atomic包 案例 package com.keytech.task; import java.util.concurrent.Executor; import java.uti ...

  2. 并发编程-04线程安全性之原子性Atomic包的4种类型详解

    文章目录 线程安全性文章索引 脑图 概述 原子更新基本类型 Demo AtomicBoolean 场景举例 原子更新数组 Demo 原子更新引用类型 Demo 原子更新字段类型 使用注意事项: Dem ...

  3. 并发编程-03线程安全性之原子性(Atomic包)及原理分析

    文章目录 线程安全性文章索引 脑图 线程安全性的定义 线程安全性的体现 原子性 使用AtomicInteger改造线程不安全的变量 incrementAndGet源码分析-UnSafe类 compar ...

  4. 并发编程-05线程安全性之原子性【锁之synchronized】

    文章目录 线程安全性文章索引 脑图 概述 原子性synchronized 修饰的4种对象 修饰代码块 作用范围及作用对象 Demo 多线程下 同一对象的调用 多线程下不同对象的调用 修饰方法 作用范围 ...

  5. 线程池,Volatile,原子性类AtomicInteger,乐观锁悲观锁,并发工具类Hashtable,ConcurrentHashMap类,Semaphore类

      目录 一.线程的状态 二.线程池 1.创建线程池的方式 1.1线程池-Executors默认线程池 1.2线程池-Executors创建指定上限的线程池 1.3线程池-ThreadPoolExec ...

  6. java 线程安全原子性_Java 线程安全之原子性

    Java 线程安全之原子性 Java 线程安全之原子性 原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可被打乱,也不可以被切割而执行其中的一部分(不可中断).将整个操作视为一个整体是原子性 ...

  7. 原子性 atomic 类用法

    当程序更新一个变量时,如果多线程同时更新这个变量,可能得到期望之外的值,比如变量i=1,A线程更新i+1,B线程也更新i+1,经过两个线程操作之后可能i不等于3,而是等于2.因为A和B线程在更新变量i ...

  8. day14 线程池、原子性、并发工具类

    目录 一.线程池 1.1 线程状态 1.2 线程池的基本原理 1.3 Executors默认线程池 1.4 创建指定上限的线程池 1.5 ThreadPoolExecutor(线程池执行器) 1.5. ...

  9. [Java多线程]-J.U.C.atomic包下的AtomicInteger,AtomicLong等类的源码解析

    Atomic原子类:为基本类型的封装类Boolean,Integer,Long,对象引用等提供原子操作. 一.Atomic包下的所有类如下表: 类摘要 AtomicBoolean 可以用原子方式更新的 ...

最新文章

  1. TFS中的测试计划(十)
  2. ISME:昆士兰大学郭建华组-人造甜味剂会促进细菌耐药性的传播
  3. 谷歌入华,抢在搜索之前的是Waymo无人驾驶
  4. 电感器在交流电路中的作用
  5. 普通Java对象怎么计算大小(字节长度)?
  6. 7-1 抓老鼠啊~亏了还是赚了? (20 分)
  7. 伪原创工具安全第一嘛~~
  8. 获取另一个驱动的设备结构体_字符设备驱动的另一种写法
  9. python比特币挖矿_比特币如何挖矿(挖矿原理)-工作量证明
  10. 【Angular 4】响应式编程
  11. python中面向对象的缺点_面向对象中的多态在 Python 中是否没有什么意义?
  12. 剑指 Offer 64. 求1+2+…+n(面试题中的短路与)
  13. linux(Centos系统)部署项目(vue+nginx+tomcat)
  14. linux英特尔蓝牙驱动,IntelBluetoothFirmware 英特尔蓝牙驱动
  15. 【Python】基于Python的百度迁徙2——迁徙规模指数(附代码)
  16. C#写简单HTML报表
  17. 模型中出现欠拟合与过拟合的应对策略
  18. 错觉图片生成实验 - 闪现的绿点
  19. python爬取微信好友信息
  20. 【NOIP 2018 提高组】填数游戏

热门文章

  1. Centos7挂载iso镜像文件配置本地yum源
  2. [Java] 蓝桥杯ALGO-118 算法训练 连续正整数的和
  3. 如何在应用系统中实现数据权限的控制功能
  4. WebLogic配置JNDI数据源
  5. perl中的sleep函数
  6. hadoop强制删除
  7. 云计算下一个十年,IT行业将发生哪些变化?
  8. Memcached原理与应用
  9. .NET Core通讯模块在Linux下的性能测试
  10. AppStore刷榜那些事儿:猪,也是这么想的