使用锁能解决并发时线程安全性,但锁的代价比较大,而且降低性能。有些时候可以使用原子类(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. Lesson 16 The modern city

    What is the author's main argument about the modern city? In the organization of industrial life the ...

  2. Activiti工作流数据库表结构

    Activiti工作流引擎数据库表结构 数据库表的命名 Acitiviti数据库中表的命名都是以ACT_开头的.第二部分是一个两个字符用例表的标识.此用例大体与服务API是匹配的. ACT_RE_*: ...

  3. Python函数-2 匿名函数

    匿名函数 当我们在创建函数时,有些时候,不需要显式地定义函数,直接传入匿名函数更方便.这省去了我们挖空心思为函数命名的麻烦,也能少写不少代码,很多编程语言都提供这一特性. Python语言使用lamb ...

  4. MNIST手写数字分类simple版(03-2)

    simple版本nn模型 训练手写数字处理 MNIST_data数据   百度网盘链接:https://pan.baidu.com/s/19lhmrts-vz0-w5wv2A97gg 提取码:cgnx ...

  5. uniGUI之新窗口uniForm(19)

    然后 保存,在这里 重命名窗口 //主窗口 调用 // NewForm2.UniForm1.Show() ; //非阻塞 NewForm2.UniForm1.ShowModal();//阻塞 //子窗 ...

  6. 如何优雅地根治null值引起的Bug!

    本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...

  7. 5.1 Nginx的基本配置

    备注:worker_processes 1(数量建议跟系统CPU的核数相同,例如:2个CPU,每个CPU4核,建议为8),worker_connections 建议小于worker_rlimit_no ...

  8. [转]ubuntu备份与恢复

    在 使用Ubuntu之前,相信很多人都有过使用Windows系统的经历.如果你备份过Windows系统,那么你一定记忆犹新:首先需要找到一个备份工 具(通常都是私有软件),然后重启电脑进入备份工具提供 ...

  9. Scrapy 中的模拟登陆

    目前,大部分网站都具有用户登陆功能,其中某些网站只有在用户登陆后才能获得有价值的信息,在爬取这类网站时,Scrapy 爬虫程序先模拟登陆,再爬取内容 1.登陆实质 其核心是想服务器发送含有登陆表单数据 ...

  10. 【剑指Offer面试编程题】题目1372:最大子向量和--九度OJ

    题目描述: HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天JOBDU测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但 ...