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相关推荐

  1. java 并发: 原子类

    相关文章:  1.原子类 ,锁  http://blog.csdn.net/youyou1543724847/article/details/52735510 2.多线程相关的 3.线程安全的集合  ...

  2. 「死磕Java并发编程」说说Java Atomic 原子类的实现原理

    <死磕 Java 并发编程>系列连载中,大家可以关注一波. 「死磕 Java 并发编程」阿里二面,面试官:说说 Java CAS 原理? 「死磕 Java 并发编程」面试官:说说什么是 J ...

  3. java并发:原子类之AtomicLong

    原子类之AtomicLong java线程中的操作,需要满足原子性.可见性等原则,比如i++这样的操作不具备原子性, A线程读取了i,另一个线程执行i++,A线程再执行i++就会引发线程安全问题 推荐 ...

  4. 彻底理解Java并发:Java并发原子类

    本篇内容包括:原子类概述.原子类分类(Atomic 基本类型原子类.Array 数组类型原子类.Atomic\Reference 引用类型原子类.Atomic\FieldUpdater 原子更新属性. ...

  5. atomic原子类实现机制_深入了解Java atomic原子类的使用方法和原理

    在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...

  6. Java使用原子类进行多线程的 i++ 操作示例

    2019独角兽企业重金招聘Python工程师标准>>> 使用AtomicInteger原子类进行 i ++ 操作 可以有类似 synchronized 实现同步的效果. 原子操作是不 ...

  7. (转)Java atomic原子类的使用方法和原理(一)

    在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...

  8. java基础-原码反码补码

    本文帮助理解,Java中原码反码补码的原理 1:原码反码补码,基础概念和计算方法 对于一个数,计算机需要使用一定的编码方式进行存储.原码反码补码是计算机存储一个具体数字的编码方式. 原码: 第一位表示 ...

  9. Java基础:子类与父类、子类与对象的关系、子类与父类同包时、不同包时的继承性

    继承:是一种由已有的类创建新类的机制. 1.利用继承这个机制,可以先定义一个共有属性的一般类,根据这个类再分别定义具有特殊属性的子类,子类继承了一般类的属性和方法,并根据自己的需求创建新的属性和方法: ...

最新文章

  1. C/C++:*(p++)慎用!!!!!
  2. 全球首次!AI研制新药物仅需18个月,李开复梁颕宇:AI医疗已突破,但只打1分...
  3. poj 1815 Friendship 最小割 拆点 输出字典序
  4. 【python技巧】“”、“”等符号操作
  5. java c 基本类型_java 基本数据类型
  6. hasp 加密 java_加密软件HASP的使用说明
  7. Go -- php 中的pack(H*, $string) 转换成go
  8. 群论及Polya计数定理题目入门
  9. 下一代SQL 产品发布会,诚邀您的参加!!包含 Azure数据服务、高级分析和SQL Server(其中包括支持Linux的SQL Server vNext)。
  10. JavaScript保留关键字及危险变量名
  11. java的科学记数法_java – 为什么输出是科学记数法?
  12. 什么是MySQL视图
  13. 群晖DSM7添加套件源
  14. 社会学概论试题库【1】
  15. C语言 简单走迷宫小游戏
  16. 解压文件到服务器是什么意思,linux中zip文件解压命令是什么
  17. Podium Vue客户端组件库
  18. Spark高级分析与机器学习笔记
  19. Python编写程序计算如下的分段函数
  20. (新SOTA)UNETR++:轻量级的、高效、准确的共享权重的3D医学图像分割

热门文章

  1. unity2018新功能之——2D Animation System
  2. Pandas数据结构:Series定义和创建
  3. 大白话学习JVM(01)| 10分钟带你走进JVM的生活
  4. 微信小程序如何正确引入iconfont图标
  5. Windows驱动中的电源管理
  6. mysql驱动程序jar包下载
  7. 【吃灰板子捡起来】LED驱动开发实验
  8. 年增长400%,天猫上这个黑马让“艺术”落地
  9. 应用在饮水机紫外线消毒灯管中的UVC杀菌灯珠
  10. 六、T100库存管理之定期盘点