java基础---多线程---JUC原子类

总结:

  1. 原子包提供了四种类型的原子类。包括基本数据类型,数组,引用类型,引用类型成员变量四种。
  2. 底层使用CAS操作保证原子性,CAS就是compare and swap先比较,如果是期望的值就进行交换。CAS是通过加总线锁或者使用内存锁定在硬件层面实现的。
  3. CAS有一些缺点:1. 单个操作能够保证原子性,但是复合操作不能够保证。2. 并发量大的时候会导致大量的循环比较操作消耗性能。 3. ABA问题。会丢失掉一些中间处理过程。
  4. 解决ABA问题使用AtomicStampedReference解决,加了一个version版本号每次判断版本。

===简述

http://www.cnblogs.com/skywang12345/p/java_threads_category.html

atomic提供了原子操作的十二个类,四种类型。

使得能够对基本数据类型,数组,对象,和对象成员进行原子操作。

原子操作指的是操作过程不会被其他线程中断。

1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;

2. 数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ;

3. 引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkableReference ;

4. 对象的属性修改类型: AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater 。

===当涉及到更新数据的操作的时候,atomic类是如何保证原子性的呢?用的是什么类的什么方法呢?

底层使用volatile来定义类中的成员变量来实现可见性。cas操作来实现原子性。

底层使用到unsafe类的三个方法compareAndSwapObject,compareAndSwapInt和compareAndSwapLong,再看AtomicBoolean源码,发现其是先把Boolean转换成整型,再使用compareAndSwapInt进行CAS,所以原子更新double也可以用类似的思路来实现。

cas操作就是一个期望值,修改值,如果当前值等于期望值,就进行修改。

===cas操作如何保证线程安全呢?在硬件上具体是如何实现的呢?

cas方法在语言方面不做任何处理,不加锁,但是实现了硬件层面的阻塞。处理器使用基于对缓存加锁或总线加锁的方式来实现多处理器之间的原子操作。

第一个机制是通过总线锁保证原子性。。如果多个处理器同时对共享变量进行读改写(i++就是经典的读改写操作)操作,那么共享变量就会被多个处理器同时进行操作,这样读改写操作就不是原子的,操作完之后共享变量的值会和期望的不一致,举个例子:如果i=1,我们进行两次i++操作,我们期望的结果是3,但是有可能结果是2。

原因是有可能多个处理器同时从各自的缓存中读取变量i,分别进行加一操作,然后分别写入系统内存当中。那么想要保证读改写共享变量的操作是原子的,就必须保证CPU1读改写共享变量的时候,CPU2不能操作缓存了该共享变量内存地址的缓存。

处理器使用总线锁就是来解决这个问题的。所谓总线锁就是使用处理器提供的一个LOCK#信号,当一个处理器在总线上输出此信号时,其他处理器的请求将被阻塞住,那么该处理器可以独占使用共享内存。

第二个机制是通过缓存锁定保证原子性。在同一时刻我们只需保证对某个内存地址的操作是原子性即可,但总线锁定把CPU和内存之间通信锁住了,这使得锁定期间,其他处理器不能操作其他内存地址的数据,所以总线锁定的开销比较大,最近的处理器在某些场合下使用缓存锁定代替总线锁定来进行优化。

http://blog.csdn.net/a953713428/article/details/54562648

===cas操作的缺点和解决方式

http://blog.csdn.net/goodlixueyong/article/details/51339689

CAS虽然很高效的实现了原子操作,但是它依然存在三个问题。

1、ABA问题。CAS在操作值的时候检查值是否已经变化,没有变化的情况下才会进行更新。但是如果一个值原来是A,变成B,又变成A,那么CAS进行检查时会认为这个值没有变化,但是实际上却变化了。ABA问题的解决方法是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就变成1A-2B-3A。从Java1.5开始JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。加了一个版本号标识,判断版本号码是否一致,一致就交换。

2、并发越高,失败的次数会越多,CAS如果长时间不成功,会极大的增加CPU的开销。因此CAS不适合竞争十分频繁的场景。

3、只能保证一个共享变量的原子操作。当对多个共享变量操作时,CAS就无法保证操作的原子性,这时就可以用锁,或者把多个共享变量合并成一个共享变量来操作。比如有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java1.5开始JDK提供了AtomicReference类来保证引用对象的原子性,你可以把多个变量放在一个对象里来进行CAS操作。

===AtomicIntegerFieldUpdater使用反射机制来进行对象成员变量的原子修改操作。同时要把接受修改的成员变量设置成volatile的类型

===LongAdder比起AtomicInteger来说有什么优势吗?

在高并发场景下LongAdder比AtomitInteger效率高很多。Atomic类主要是依靠CAS操作保证同步的,但是缺点就是因为是单点更新只有一个value值,所以高并发下CAS失败的几率很高,重复操作就很多,消耗性能。

LongAdder的优势就是在低并发场景下,使用和Atomic一样的CAS原子更新,但是在高并发场景下使用分点更新的手段。维护了一个Cell数组,cell里面有个value存值,高并发场景下线程分配到不同的Cell中去更新相应的value值,也就是分段更新操作,需要总数的时候加起来就可以了。

原文地址:https://www.cnblogs.com/buptyuhanwen/p/9546698.html

时间: 2024-08-30 04:44:17

java基础---多线程---JUC原子类的相关文章

Java单例模式结合JUC原子类爆发的新想法

单例模式是23种设计模式中的一种,关于它的介绍,已经数不胜数了,一般网上的实现方式无非是什么懒汉式,饿汉式,内部类,枚举,volatile加双重校验锁等等,今天我又想到一个新的实现方式,利用J.U.C提供的原子类,代码如下: class SingleTon { private static AtomicReference<SingleTon> reference = new AtomicReference<>(); private SingleTon() { } public st

java多线程系类:JUC原子类:03之AtomicLongArray原子类

概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数组类型的原子类进行介绍.内容包括:AtomicLongArray介绍和函数列表AtomicLongArray源码分析(基于JDK1.7.0_40)AtomicLongArray示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3514604.html

JAVA多线程之JUC原子类

JUC原子类框架 JUC即是指:java.util.concurrent包. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ; 数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ; 引用类型: AtomicReference, AtomicStampedRerence, AtomicMarkab- leReference ; 对象的属性修改类型: AtomicIntege

黑马程序员——java基础——多线程

 黑马程序员--java基础--多线程 ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 进程:是一个正在执行中的程序.每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控制单元. 线程:就是进程中的一个独立的控制单元.线程在控制着进程的执行.一个进程中至少有一个线程. 一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区.自己的变量.

Java基础——多线程(1)

进程:应用程序在内存中分配的空间(正在运行的程序). 线程:是进程中负责程序执行的执行单元,也称为执行路径. 一个进程中至少有一个线程,在负责该进程的运行. 如果一个进程中出现了多个线程,就称为该程序为多线程程序. 多线程技术:解决多部分代码同时执行的需求,合理使用CPU资源. 多线程的运行是根据CPU的切换完成的,怎么切换是CPU说的算.所多线程运行有一个随机性(CPU快速切换造成的). jvm中的多线程: 至少有两个线程,一个是负责自定义代码运行的,一个是负责垃圾回收的. 发现结果并不相同,

Java基础-多线程-③多线程的同步之synchronized

使用线程同步解决多线程安全问题 上一篇 Java基础-多线程-②多线程的安全问题 中我们说到多线程可能引发的安全问题,原因在于多个线程共享了数据,且一个线程在操作(多为写操作)数据的过程中,另一个线程也对数据进行了操作,从而导致数据出错.由此我们想到一个解决的思路:将操作共享数据的代码行作为一个整体,同一时间只允许一个线程执行,执行过程中其他线程不能参与执行.线程同步就是用来实现这样的机制. synchronized代码块 Java中提供了synchronized关键字,将可能引发安全问题的代码

Java基础-多线程-②多线程的安全问题

什么是线程的安全问题? 上一篇 Java基础-多线程-①线程的创建和启动 我们说使用实现Runnable接口的方式来创建线程,可以实现多个线程共享资源: 1 class Dog implements Runnable { 2 // 定义线程共享数据 3 private int t = 100; 4 5 @Override 6 public void run() { 7 // TODO:死循环,暂不处理 8 while (true) { 9 if (t > 0) { 10 11 System.ou

Java多线程系列---“JUC原子类”01之 原子类的实现(CAS算法)

转自:https://blog.csdn.net/ls5718/article/details/52563959  & https://blog.csdn.net/mmoren/article/details/79185862(含部分修改) 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. (2)一个线程持有锁会导致其它所有需要此锁的线程挂起. (3)

java多线程系类:JUC原子类:04之AtomicReference原子类

概要 本章对AtomicReference引用类型的原子类进行介绍.内容包括:AtomicReference介绍和函数列表AtomicReference源码分析(基于JDK1.7.0_40)AtomicReference示例 转载请注明出处:http://www.cnblogs.com/skywang12345/p/3514623.html AtomicReference介绍和函数列表 AtomicReference是作用是对"对象"进行原子操作. AtomicReference函数列