使用锁能解决并发时线程安全性,但锁的代价比较大,而且降低性能。有些时候可以使用原子类(juc-atomic包中的原子类)。还有一些其他的非加锁式并发处理方式,我写这篇文章来源于Java中有哪些无锁技术来解决并发问题的思考。

1.原子类场景
    刚才说了,原子类是在不加锁的情况下,实现并发安全。我们知道锁synchronized/lock能实现并发安全的三点要求:原子性、可见性和有序性。而原子类顾名思义可以保证原则性其他两点不能确定(我是边想边写的,后面我会给出结论)。
好吧,写不下去了,还是看看现成的总结吧。百度收索“Java原子类使用场景”,随便点开两个,基本上都是通过举了一个“多线程计数”的例子来说明使用场景+底层使用CAS来总结原理。好了这里我就得出结论原子类使用场景之一多线程计数器的实现。后面如果找到更好的总结再补充。
这里说一句废话,看似我在写一些没有用心总结的东西,也不会有人看,网上这样的文章一堆,我干嘛要写呢,我告诉你,我主要是形成自己关于这块的知识的痕迹,写的虽然不怎么的,但至少我也是按结构,经过思考过的输出产品。这一系列的文章最终能搭建我的知识体系,知识体系一旦搭建完成,就能建立知识地图,快速反应和检索,思考和工作效率得到提升。我深信这一点。

#####2.原子类分类
```
分类这块看到一个比较好的总结,[Java16个原子类介绍-基于JDK8](https://blog.csdn.net/weixin_38003389/article/details/88569336),讲的很全面,每个都有例子说明
总结一下:
1.jdk8之前共12个,jdk8新增了4个
2.具体分类
a.原子基本类型:AtomicInteger、AtomicBoolean、AtomicLong
b.原子数组(通过原子操作的方式更新数组中元素):AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
c.原子引用类型:AtomicRerence、AtomicMarkableReference
d.原子字段类(通过原子操作更新某个类的字段):AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedFieldUpdater、AtomicReferenceFieldUpdater
e.jdk8新增:DoubleAccumulator、LongAccumulator、DoubleAdder、LongAdder

    3.具体使用注意
a.要想使用原子字段类需要两步。第一步,因为原子更新字段类都是抽象类,每次使用的时候必须使用静态方法newUpdater()创建一个更新器,并且需要设置想要更新的类和属性。第二步,更新类的字段必须使用 public volatile 修饰。
<br>
#####3.原子类实现原理
a.大多数使用Unsafe类的CAS原子指令。

b.jdk8新增的LongAdder使用的不是Unsafe的CAS原理,而是类似的思想,下图很好的说明了这种思想。LongAdder不可以代替AtomicLong  ,虽然 LongAdder 的 add() 方法可以原子性操作,但是并没有使用 Unsafe 的CAS算法,只是使用了CAS的思想。
![](https://img2018.cnblogs.com/blog/1012214/202001/1012214-20200122180604029-714306250.jpg)
如图LongAdder则是内部维护多个变量,每个变量初始化都0,在同等并发量的情况下,争夺单个变量的线程量会减少这是变相的减少了争夺共享资源的并发量,另外多个线程在争夺同一个原子变量时候如果失败并不是自旋CAS重试,而是尝试获取其他原子变量的锁,最后获取当前值时候是把所有变量的值累加后返回的(不一定准确,没有并发情况下真实)。 <br>
#####4.原子类使用demo

public class TestAtomicInteger {

static Integer count = 0;

public static void main(String[] args){
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100000; i++) {
count++;
}
System.out.println("thread1 count add 100000 over");
}
}); Thread thread2 = new Thread(new Runnable() {
@Override
public void run() { for (int i = 0; i < 100000; i++) {
count++;
}
System.out.println("thread2 count add 100000 over");
}
}); thread1.start();
thread2.start(); try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("最终:"+count); }

}

//该例子输出的结果并不是200000,而是小于它,只需要把count的类型改为AtomicInteger即可(前面不需要加volatile关键字)。

java核心-多线程(8)- 并发原子类的更多相关文章

  1. Java多线程系列--“JUC原子类”02之 AtomicLong原子类

    概要 AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似.本章以AtomicLong对基本类型的原子类进行介绍.内容包括:Atomic ...

  2. Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

    概要 AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似.本章以AtomicLongArray对数 ...

  3. Java多线程系列--“JUC原子类”04之 AtomicReference原子类

    概要 本章对AtomicReference引用类型的原子类进行介绍.内容包括:AtomicReference介绍和函数列表AtomicReference源码分析(基于JDK1.7.0_40)Atomi ...

  4. Java多线程系列--“JUC原子类”05之 AtomicLongFieldUpdater原子类

    概要 AtomicIntegerFieldUpdater, AtomicLongFieldUpdater和AtomicReferenceFieldUpdater这3个修改类的成员的原子类型的原理和用法 ...

  5. java 多线程系列---JUC原子类(三)之AtomicLongArray原子类

    AtomicLongArray介绍和函数列表 在"Java多线程系列--“JUC原子类”02之 AtomicLong原子类"中介绍过,AtomicLong是作用是对长整形进行原子操 ...

  6. java并发:原子类之AtomicLong

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

  7. java核心-多线程(1)-知识大纲

    Thread,整理一份多线程知识大纲,大写意 1.概念介绍 线程 进程 并发 2.基础知识介绍 Java线程类 Thread 静态方法&实例方法 Runnable Callable Futur ...

  8. Java并发—原子类,java.util.concurrent.atomic包(转载)

    原子类 Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中 的原子操作类提供了一种用法简单.性能高效.线程安全地更新一个变量 ...

  9. java 多线程系列---JUC原子类(二)之AtomicLong原子类

    概要 AtomicInteger, AtomicLong和AtomicBoolean这3个基本类型的原子类的原理和用法相似.本章以AtomicLong对基本类型的原子类进行介绍. AtomicLong ...

随机推荐

  1. Java通过反射实现实例化

    public static void main(String[] args) throws Exception { User user= (User) test(User.class); System ...

  2. day2-2循环语句

    ECMAScript不存在块级作用域,在循环内部定义的变量也可以在外部访问到 局部变量与全局变量: 1) 使用var操作符定义的变量将成为定义该变量的作用域中的局部变量. 2) 如果在函数中定义变量没 ...

  3. 内核运行时数据结构的操作(启用路由功能),sysctl内核设置命令

    LINUX系统运行时,内核数据结构数据的修改,系统提供了统一抽象的文件操作接口(命名空间操作接口)比如启用路由功能echo  1 > proc/sys/net/ipv4/ip-forward// ...

  4. 十 Spring的AOP的底层实现:JDK动态代理和Cglib动态代理

    SpringAOP底层的实现原理: JDK动态代理:只能对实现了接口的类产生代理.(实现接口默认JDK动态代理,底层自动切换) Cglib动态代理(类似Javassist第三方的代理技术):对没有实现 ...

  5. C# 读取和写入txt文件

    读取: 1.使用StreamReader读取文件,然后一行一行的输出 StreamReader sr = new StreamReader(path,Encoding.Default); String ...

  6. 吴裕雄--天生自然python数据清洗与数据可视化:MYSQL、MongoDB数据库连接与查询、爬取天猫连衣裙数据保存到MongoDB

    本博文使用的数据库是MySQL和MongoDB数据库.安装MySQL可以参照我的这篇博文:https://www.cnblogs.com/tszr/p/12112777.html 其中操作Mysql使 ...

  7. shell脚本中执行sql命令

    1.mysql 数据库表信息 2.shell脚本(a.sh)信息 #!/bin/sh mysql -u root << myInsert insert into test.t values ...

  8. android下创建文件夹和修改其权限的方法

    原文:http://www.cnblogs.com/wanqieddy/archive/2011/12/28/2304906.html 由于工作的需要,今天研究了在android下创建文件夹和修改其权 ...

  9. 本地启动tomcat的时候报java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: PermGen space

    1.问题:我在tomcat中放入了大量的war包,启动的时候报:java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: ...

  10. <audio>音频标签

    <audio ref="audio" @canplay="ready" @error="error"  @timeupdate=&qu ...