Java基础-原子类、CAS
1、什么是原子类
- 原子类的作用和锁类似,是为了保证并发情况下的线程安全。不过原子类相比锁,有一定优势
- 粒度更细:他锁的范围更小
- 效率更高:相比于锁,效率更高,除了高度竞争的情况
2、6类原子类
- Atomic*基本类型原子类:AtomicInteger、AtomicLong、AtomicBoolean
- Atomic*Array数组类型原子类:AtomicIntegerArray、AtomicLongArray、AtomicBooleanArray
- Atomic*Reference引用类型原子类:AtomicReference、AtomicStampedRefence、AtomicMarkableRenfence
- Atomic*FieldUpdater升级类型原子类:AtomicIntegerfiedupdater、AtomicLongFieldUpdater、AtomicRefenceFieldUpdater
- Adder累加器:LongAdder、DoubleAdder
- Accumulator累加器:LongAccumulator、DoubleAccumulator
3、Atomic*基本类型原子类
基于CAS操作实现原子性
3.1、AtomicInteger常用方法
- get()获取当前的值
- getAndSet(int newValue)获取当前的值,并设置新的值
- getAndIncrement()获取当前的值,并自增
- getAndDecrement()获取当前的值,并自减
- getAndAdd(int delta)获取当前的值,并加上预期的值
- compareAndSet(int expect, int update)如果当前的值等于预期的值,则以原子方式将值设置为输入值
public class AtomicIntegerDemo1 implements Runnable {private static final AtomicInteger atomicInteger = new AtomicInteger();public void incrementAtomic(){atomicInteger.getAndIncrement();}private static volatile int basicCount = 0;public void incrementBasic(){basicCount++;}public void run() {for (int i = 0; i < 10000; i++) {incrementAtomic();incrementBasic();}}public static void main(String[] args) throws InterruptedException {AtomicIntegerDemo1 r = new AtomicIntegerDemo1();Thread thread1 = new Thread(r);Thread thread2 = new Thread(r);thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("原子类的结果" + atomicInteger.get());System.out.println("普通变量的结果" + basicCount);} }
4、Atomic*Array数组类型原子类
可以保证一个数组中所有的原子操作
public class AtomicArrayDemo {public static void main(String[] args) throws InterruptedException {AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(1000);Incrementer incrementer = new Incrementer(atomicIntegerArray);Decrementer decrementer = new Decrementer(atomicIntegerArray);Thread[] threadsIncrement = new Thread[100];Thread[] threadsDecrement = new Thread[100];for (int i = 0; i < 100; i++) {threadsDecrement[i] = new Thread(decrementer);threadsIncrement[i] = new Thread(incrementer);threadsDecrement[i].start();threadsIncrement[i].start();}for (int i = 0; i < 100; i++) {threadsDecrement[i].join();threadsIncrement[i].join();}for (int i = 0; i < atomicIntegerArray.length(); i++) {if (atomicIntegerArray.get(i) != 0){System.out.println("发现了非0值,位置"+i);}}System.out.println("运行结束");}} class Decrementer implements Runnable{private AtomicIntegerArray array;public Decrementer(AtomicIntegerArray array){this.array = array;}public void run() {for (int i = 0; i < array.length(); i++) {array.getAndDecrement(i);}} } class Incrementer implements Runnable{private AtomicIntegerArray array;public Incrementer(AtomicIntegerArray array){this.array = array;}public void run() {for (int i = 0; i < array.length(); i++) {array.getAndIncrement(i);}} }
5、Atomic*Reference引用类型原子类
和AtomicInteger本质上没有区别,这个是针对于对象
public class SpinLock {private AtomicReference<Thread> sign = new AtomicReference<>();public void loock(){Thread currentThread = Thread.currentThread();while (!sign.compareAndSet(null, currentThread)){System.out.println("自旋获取失败,再次尝试");}}public void unlock(){Thread currentThread = Thread.currentThread();sign.compareAndSet(currentThread, null);}public static void main(String[] args) {SpinLock spinLock = new SpinLock();Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "尝试获取自旋锁");spinLock.loock();System.out.println(Thread.currentThread().getName() + "获取到了自旋锁");try {Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();} finally {spinLock.unlock();System.out.println(Thread.currentThread().getName() + "释放了自旋锁");}}};new Thread(runnable).start();new Thread(runnable).start();} }
主要是使用了compareAndSet()方法
6、Atomic*FieldUpdater升级类型原子类
将普通变量升级为具有原子功能
public class AtomicIntegerFieldUpdaterDemo implements Runnable {static Candidate tom;static Candidate peter;public static AtomicIntegerFieldUpdater<Candidate> scoreUpdater =AtomicIntegerFieldUpdater.newUpdater(Candidate.class, "score");public void run() {for (int i = 0; i < 10000; i++) {peter.score++;// tom.score++;scoreUpdater.getAndIncrement(tom);}}public static class Candidate{volatile int score;}public static void main(String[] args) throws InterruptedException {tom = new Candidate();peter = new Candidate();AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();Thread thread1 = new Thread(r);Thread thread2 = new Thread(r);thread1.start();thread2.start();thread1.join();thread2.join();System.out.println("普通的变量:"+peter.score);System.out.println("升级后的的变量:"+tom.score);} }
使用的是反射的机制,且不支持被static修饰的变量
7、Adder累加器
- 是Java8引入的,想对是比较新的一个类
- 高并发下LongAdder比AtomicLong效率高,不过本质是空间换时间
- 竞争激励的时候,LongAdder把不同线程对应到不同的Cell上进行修改,降低了冲突的概率,是多段锁的理念,提高了并发性
AtomicLong的耗时
public class AtomicLongDemo {public static void main(String[] args) {AtomicLong counter = new AtomicLong(0);ExecutorService executorService = Executors.newFixedThreadPool(20);long start = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {executorService.submit(new Task(counter));}executorService.shutdown();while (!executorService.isTerminated()){}long end = System.currentTimeMillis();System.out.println("耗费时间="+(end-start));}private static class Task implements Runnable{private AtomicLong counter;public Task(AtomicLong counter){this.counter = counter;}public void run() {for (int i = 0; i < 10000; i++) {counter.incrementAndGet();}}} }
使用LongAdder提升性能
public class LongAdderDemo {public static void main(String[] args) {LongAdder counter = new LongAdder();ExecutorService executorService = Executors.newFixedThreadPool(20);long start = System.currentTimeMillis();for (int i = 0; i < 10000; i++) {executorService.submit(new LongAdderDemo.Task(counter));}executorService.shutdown();while (!executorService.isTerminated()){}long end = System.currentTimeMillis();System.out.println("耗费时间="+(end-start));}private static class Task implements Runnable{private LongAdder counter;public Task(LongAdder counter){this.counter = counter;}public void run() {for (int i = 0; i < 10000; i++) {counter.increment();}}} }
AtomicLong每次自增都是需要flush和refersh
LongAdder,每个线程都会有自己的一个计数器,仅用来在自己的线程内计数,这样一来就不会和其他线程的计数器干扰
LongAdder只使用于统计求和的场景
8、Accumulator累加器
适用于大的数据量计算,并且对计算顺序不要求
public class LongAccumulatorDemo {public static void main(String[] args) {//LongAccumulator()后面的参数为x,后面传递的参数为yLongAccumulator accumulator = new LongAccumulator((x, y) -> x + y, 0);accumulator.accumulate(1);accumulator.accumulate(2);System.out.println(accumulator.get());} }
9、CAS
- CAS作用于并发,保证一些列操作是原子性
- 思想:我认为V的值应该是A,如果是的话那我就将它改成B,如果不是A(说明被别人修改过了),那我就不修改了,避免多人同时修改出错
- CAS有三个操作数:内存值V、预期值A、要修改的值B。当预期值A和内存值V相同时,才将内存值修改为B,否则什么都不做。最后返回现在的值
- CAS最终是利用CPU的指令来完成,CPU保证了原子性
CAS的等价代码:
public class SimulatedCAS {private volatile int value;//整个方法模拟cpu的一条指令,原子性public synchronized int compareAndSwap(int expectedValue, int newValue){int oldValue = value;if (oldValue == expectedValue){value = newValue;}return oldValue;} }
使用两个线程来模拟多线程中CAS操作
public class TwoThreadCompetition implements Runnable{private volatile int value;//整个方法模拟cpu的一条指令,原子性public synchronized int compareAndSwap(int expectedValue, int newValue){int oldValue = value;if (oldValue == expectedValue){value = newValue;}return oldValue;}@Overridepublic void run() {compareAndSwap(0, 1);}public static void main(String[] args) throws InterruptedException {TwoThreadCompetition r = new TwoThreadCompetition();r.value = 0;Thread t1 = new Thread(r, "Thread1");Thread t2 = new Thread(r, "Thread2");t1.start();t2.start();t1.join();t2.join();System.out.println(r.value);} }
典型的应用场景
- 乐观锁
- 并发容器
- 原子类
AtomicInteger中使用的源码
public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updates//java无法访问直接访问/unsafe 给我们提供了硬件级别的原子private static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}private volatile int value;......public final int getAndAddInt(Object var1, long var2, int var4) {//do while自旋,不停的尝试int var5;do {var5 = this.getIntVolatile(var1, var2);} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));return var5;} }
CAS的缺点:
- ABA问题:他只是检查值是否相等,相等不代表没有被修改过。原来是5,可能A线程改为7,B线程改为5,对比后,发现还是5,但是值确实被修改过。解决方案:版本号
- 自旋时间可能过长,因为他是一个自旋,对性能有很多的消耗
Java基础-原子类、CAS相关推荐
- java 并发: 原子类
相关文章: 1.原子类 ,锁 http://blog.csdn.net/youyou1543724847/article/details/52735510 2.多线程相关的 3.线程安全的集合 ...
- 「死磕Java并发编程」说说Java Atomic 原子类的实现原理
<死磕 Java 并发编程>系列连载中,大家可以关注一波. 「死磕 Java 并发编程」阿里二面,面试官:说说 Java CAS 原理? 「死磕 Java 并发编程」面试官:说说什么是 J ...
- java并发:原子类之AtomicLong
原子类之AtomicLong java线程中的操作,需要满足原子性.可见性等原则,比如i++这样的操作不具备原子性, A线程读取了i,另一个线程执行i++,A线程再执行i++就会引发线程安全问题 推荐 ...
- 彻底理解Java并发:Java并发原子类
本篇内容包括:原子类概述.原子类分类(Atomic 基本类型原子类.Array 数组类型原子类.Atomic\Reference 引用类型原子类.Atomic\FieldUpdater 原子更新属性. ...
- atomic原子类实现机制_深入了解Java atomic原子类的使用方法和原理
在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...
- Java使用原子类进行多线程的 i++ 操作示例
2019独角兽企业重金招聘Python工程师标准>>> 使用AtomicInteger原子类进行 i ++ 操作 可以有类似 synchronized 实现同步的效果. 原子操作是不 ...
- (转)Java atomic原子类的使用方法和原理(一)
在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...
- java基础-原码反码补码
本文帮助理解,Java中原码反码补码的原理 1:原码反码补码,基础概念和计算方法 对于一个数,计算机需要使用一定的编码方式进行存储.原码反码补码是计算机存储一个具体数字的编码方式. 原码: 第一位表示 ...
- Java基础:子类与父类、子类与对象的关系、子类与父类同包时、不同包时的继承性
继承:是一种由已有的类创建新类的机制. 1.利用继承这个机制,可以先定义一个共有属性的一般类,根据这个类再分别定义具有特殊属性的子类,子类继承了一般类的属性和方法,并根据自己的需求创建新的属性和方法: ...
最新文章
- C/C++:*(p++)慎用!!!!!
- 全球首次!AI研制新药物仅需18个月,李开复梁颕宇:AI医疗已突破,但只打1分...
- poj 1815 Friendship 最小割 拆点 输出字典序
- 【python技巧】“”、“”等符号操作
- java c 基本类型_java 基本数据类型
- hasp 加密 java_加密软件HASP的使用说明
- Go -- php 中的pack(H*, $string) 转换成go
- 群论及Polya计数定理题目入门
- 下一代SQL 产品发布会,诚邀您的参加!!包含 Azure数据服务、高级分析和SQL Server(其中包括支持Linux的SQL Server vNext)。
- JavaScript保留关键字及危险变量名
- java的科学记数法_java – 为什么输出是科学记数法?
- 什么是MySQL视图
- 群晖DSM7添加套件源
- 社会学概论试题库【1】
- C语言 简单走迷宫小游戏
- 解压文件到服务器是什么意思,linux中zip文件解压命令是什么
- Podium Vue客户端组件库
- Spark高级分析与机器学习笔记
- Python编写程序计算如下的分段函数
- (新SOTA)UNETR++:轻量级的、高效、准确的共享权重的3D医学图像分割