一、新增原子类LongAdder

  LongAdder是JDK8中AtomicLong的增强工具类,它与AtomicLong最大的不同就是:在多线程场景下,LongAdder中对单一的变量进行拆分成多个变量,这些变量分为两类base和Cell。base是基础值,默认一般为0;而Cell就是我们所拆分的值,它可以有多个。所以当获取LongAdder的值时就是把base和每个Cell的值相加。

  为什么要拆分成多个Cell呢?这是因为在多线程场景下,如果多个线程都在对同一个变量进行操作,为了使这个变量原子性,我们不得不对起加锁,这样就大大的降低了程序的性能。但是如果把这个变量拆分为多个Cell,虽然还是会给每个Cell加锁,但是线程访问的变量就是不是同一个了,可以进行异步操作。

  关于Cell的特点:

  1.Cell采用懒加载机制,这是因为Cell占的内存空间相对比较大的。开始只会创建Base,只有当有其他线程来竞争资源时,才会拆分为多个Cell;

  2.Cell的初始化值为2,每次扩容是2的N次方;

  3.Cell本质是一个数组,它的元素最大值为 CPU 核数;

  4.Cell 扩容条件: casCellsBusy 为 false 没有库容;有线程竞争资源;cell的数量没有超过 CPU的核数。
 

我们来看一个例子,用LongAdder声明一个值,使这个值加10000*10次,10为线程数:

  

public class ThreadLongAdder implements Runnable {

    //给线程方法传递一个参数
static LongAdder count = new LongAdder(); /**
* 线程任务,将count的值相加10000*10次
*/
public void run() {
System.out.println("当前线程获取count的值为:" + count);
for (int i = 0; i < 10000; i++) {
long num = 1l;
count.add(num);
}
} public static void main(String[] args) throws InterruptedException {
//创建多线程环境,这里创建了10个线程
Thread[] thread = new Thread[10];
//未创建的多线程中添加线程任务
for (int i = 0; i < 10; i++) {
thread[i] = new Thread(new ThreadLongAdder());
}
//启动每个线程任务
for (int i = 0; i < 10; i++) {
thread[i].start();
}
//join方法的作用是阻塞主线程,防止还没有计算完成,就开始输出count的值了
for (int i = 0; i < 10; i++) {
thread[i].join();
}
System.out.println("count计算的结果是:" + count);
} }

结果为:

  

二、增强锁stampedlock

  stampedlock是JDK8中新增的加强读写锁。我们知道在高并发场景下,读写锁中读锁与写锁是互斥的,如果当环境中读的操作过多,写的较少,就会导致写操作的线程产生饥饿现象。

  对于饥饿现象我们一般会考虑使用公平锁,但是公平锁会大大降低程序的性能。所以为了解决这一问题,JDK8为我们新增了stampedlock来解决。

  stampedlock的特点:

  1. 获取锁的时候,会给获取锁的方法返回一个Stamp,当Stamp的值为0时,表示获取失败。当然释放锁的时候没,释放的方法中必须要有获取锁的时候得到的Stamp。这样做的好处是能够提供读写互斥的性能。
  2. StampedLock是不可重入锁,如果两个方法获取了同一把锁,那么就会发生死锁;
  3. StampedLock中为我们提供了3把锁:
    ①Reading(读锁):类似于ReentrantReadWriteLock的读锁
    ②Writing(写锁):类似于ReentrantReadWriteLock的写锁
    ③Optimistic reading(乐观读模式):这是StampedLock为我们提供的一把优化锁
  4. StampedLock支持读锁和写锁的相互转换
    我们知道RRW中,当线程获取到写锁后,可以降级为读锁,但是读锁是不能直接升级为写锁的。
    StampedLock提供了读锁和写锁相互转换的功能,使得该类支持更多的应用场景。
  5. 无论写锁还是读锁,都不支持Conditon等待

  我们来看一个stampedlock使用的例子:

  线程任务类:

  

public class StampedlockDemo extends Thread{

     StampedLock stampedLock = new StampedLock();

     int num;

    static int sum;

    /***
* 这是线程任务,先写再读
*/
@Override
public void run() {
// 获取写锁,Long类型表示Stamp的值,如果是0就获取失败
Long write = stampedLock.writeLock();
if (write != 0L) {
System.out.println("现在进行写的操作");
// 要写的方法
sum += num;
}
// 转换为读锁
Long read = stampedLock.tryConvertToOptimisticRead(write);
if (read != 0L) {
// 要读的内容
System.out.println("现在进行的读操作,当前的值为:");
System.out.println(sum);
}
} public StampedlockDemo(StampedLock stampedLock, int num) {
super();
this.stampedLock = stampedLock;
this.num = num;
} }

  测试类:

public class Main {

    public static void main(String[] args) {
//创建锁对象
StampedLock stampedLock = new StampedLock();
//创建三个线程
StampedlockDemo stampedlockDemo1=new StampedlockDemo(stampedLock,1);
StampedlockDemo stampedlockDemo2=new StampedlockDemo(stampedLock,10);
StampedlockDemo stampedlockDemo3=new StampedlockDemo(stampedLock,100);
stampedlockDemo3.start();
stampedlockDemo1.start();
stampedlockDemo2.start(); }
}

运行结果:

  

java并发学习--第八章 JDK 8 中线程优化的新特性的更多相关文章

  1. Java并发学习之二——获取和设置线程信息

    本文是学习网络上的文章时的总结,感谢大家无私的分享. Thread类的对象中保存了一些属性信息可以帮助我们辨别每个线程.知道它的一些信息 ID:每一个线程的独特标示: Name:线程的名称: Prio ...

  2. java并发学习--第二章 spring boot实现线程的创建

    除了之前介绍的创建线程方式外,spring boot为我们了提供一套完整的线程创建方式,其中包括了:线程.线程池.线程的监控. 一.使用spring boot提供的方法创建线程与线程池 1.首先在sp ...

  3. Oracle12c中性能优化增强新特性之数据库智能闪存

    智能闪存功能最初在XD中引入.从Oracle11.2.0.2开始,除了用于XD存储,还可用于任何闪盘.Oracle12c中,不需卷管理器就可以使用闪盘. 1.  简介 智能闪存在solaris和lin ...

  4. Java并发编程系列-(9) JDK 8/9/10中的并发

    9.1 CompletableFuture CompletableFuture是JDK 8中引入的工具类,实现了Future接口,对以往的FutureTask的功能进行了增强. 手动设置完成状态 Co ...

  5. “全栈2019”Java第八十八章:接口中嵌套接口的应用场景

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  6. “全栈2019”Java第五十八章:多态中方法返回类型可以是子类类型

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  7. Java 9 揭秘(20. JDK 9中API层次的改变)

    Tips 做一个终身学习的人. 在最后一章内容中,主要介绍以下内容: 下划线作为新关键字 改进使用try-with-resources块的语法 如何在匿名类中使用<>操作符 如何在接口中使 ...

  8. 从源码学习Java并发的锁是怎么维护内部线程队列的

    从源码学习Java并发的锁是怎么维护内部线程队列的 在上一篇文章中,凯哥对同步组件基础框架- AbstractQueuedSynchronizer(AQS)做了大概的介绍.我们知道AQS能够通过内置的 ...

  9. Java并发学习(一):进程和线程

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 俗话说得好"一人 ...

随机推荐

  1. 尚硅谷Docker---docker安装及简介

    尚硅谷Docker---docker安装及简介 一.总结 一句话总结: docker就相当于是一个极微型的linux系统,独立 1.使用Docker的步骤? 1).安装Docker 2).去Docke ...

  2. PM项目跟进护航文档模板

    护航文档 版本需求列表 需求 开发责任人 MMDrawerController.GCDTimer.Speex_armv7s等11个库迁移 熊文杰 相关人员 职称 开发人员 开发 熊文杰 测试 xxx ...

  3. webpack配置之webpack.config.js文件配置

    webpack配置之webpack.config.js文件配置 webpack.config.js webpack resolve  1.总是手动的输入webpack的输入输出文件路径,是一件非常繁琐 ...

  4. WINDOWS API 大全(二)

    9. API之设备场景函数 CombineRgn 将两个区域组合为一个新区域CombineTransform 驱动世界转换.它相当于依顺序进行两次转换CreateCompatibleDC 创建一个与特 ...

  5. Vue知识整理10:条件渲染(v-if v-show)

    在Vue中使用v-if等条件实现条件的判断来实现对象的显示. 也可以采用 v-show条件来实现对象的显示.

  6. java jna 调用windows动态链接库

    import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; import com.sun.j ...

  7. 【HANA系列】SAP HANA日期函数总结

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA日期函数总结   ...

  8. 【MM系列】SAP 物料帐下修改物料的价格

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP 物料帐下修改物料的价格   ...

  9. python中的装饰器练习

    一:编写装饰器,为多个函数加上认证的功能(用户的账号密码) 要求登录成功一次,后续的函数都无需输入用户名和密码FLAG=False#此时还未登录 全局变量 写这个步骤的意义在于:方便 知道已经登录成功 ...

  10. java8 stream取出 最大值/最小值

    注:转载请注明出处!!! 这里直接用取出多个对象中某个值 最大/最小 来进行举例 直接看代码 /** * 时间测试类 */ class TimeTest { private Date time; pu ...