热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

深入解析JDK1.8中的并发新功能与优化

JDK1.8引入了多项并发新特性,显著提升了编程效率。本文重点探讨了LongAdder和StampedLock的特性和应用场景。此外,还介绍了在多线程环境中发生死锁时,如何通过jps命令进行诊断和排查,提供了详细的步骤和示例。这些改进不仅增强了系统的性能,还简化了开发者的调试工作。

JDK1.8中有一些并发的新特性,可以提高变成的效率。本文写的主要是LongAdder和stampedlock的特性。
多线程发生死锁时dump查看方式:
使用命令jps:如下所示
这里写图片描述

通过这个命令我们可以得到死锁号,然后再通过命令jstack查看

如下所示:
这里写图片描述

LongAdder

LongAdder是什么?
在大数据处理过程,为了方便监控,需要统计数据,少不了原子计数器。为了尽量优化性能,需要采用高效的原子计数器。在jdk8中,引入了LongAdder,非常适合多线程原子计数器。
我们知道,AtomicLong已经是非常高效的了,涉及并发的地方都是使用CAS(无锁)操作,在硬件层次上去做 compare and set操作。效率非常高。
LongAdder比AtomicLong更加高效。

实现原理:
LongAdder 沿用了concurrentMap原理,他是将1个整数拆分成一个数组cells,数组中有若干个cell。若有多个线层,每个线程通过CAS更新其中的一个小cell。然后内部将数组做sum求和操作得到整数的value;
这样就使得AtomicLong的单一线程做CAS操作演变成多个线程同时做CAS操作,期间互不影响。从而提高效率;
LongAdder开始并没有做拆分,当多线程间执行遇到冲突时才会拆分cell,若是多线程执行始终没有冲突,则它相当于AtomicLong;

如何分配cell的???
拿到线程相关的HashCode对象后,获取它的code变量,计算出一个在Cells 数组中当前线程的HashCode对应的索引位置,并将该位置的Cell 对象拿出来用CAS更新它的value值。

LongAdder的继承树
这里写图片描述

LongAdder的方法
这里写图片描述

使用案例

import java.util.concurrent.atomic.LongAdder;

public class LongAdderTest {

    private static LongAdder la =new LongAdder();

    public static int a =0;
    public static void add(){
        la.increment();
        a++;
    }
    /** * @param args * @throws InterruptedException */
    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        Thread t1 = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                for(int i=0;i<10000;i++){
                    add();
                }
            }
        });
        t1.start();

        Thread t2 = new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                for(int i=0;i<10000;i++){
                    add();
                }
            }
        });
        t2.start();
        t1.join();t2.join();
        System.out.println("---la-----"+la);
        System.out.println("---a-----"+a);
    }

}

执行结果:
这里写图片描述

StampedLock

stampedLock推出了乐观读锁,在使用乐观读锁时,不会阻塞写锁,这使得我们在写数据时,不会因为使用读锁而长时间的阻塞写,从而提高效率;
ReentrantReadWriteLock 在沒有任何读写锁时,才可以取得写入锁,这可用于实现了悲观读取(Pessimistic Reading),即如果执行中进行读取时,经常可能有另一执行要写入的需求,为了保持同步,ReentrantReadWriteLock 的读取锁定就可派上用场。
然而,如果读取执行情况很多,写入很少的情况下,使用 ReentrantReadWriteLock 可能会使写入线程遭遇饥饿(Starvation)问题,也就是写入线程迟迟无法竞争到锁定而一直处于等待状态。
StampedLock控制锁有三种模式(写,读,乐观读),一个StampedLock状态是由版本和模式两个部分组成,锁获取方法返回一个数字作为票据stamp,它用相应的锁状态表示并控制访问,数字0表示没有写锁被授权访问。在读锁上分为悲观锁和乐观锁。
所谓的乐观读模式,也就是若读的操作很多,写的操作很少的情况下,你可以乐观地认为,写入与读取同时发生几率很少,因此不悲观地使用完全的读取锁定,程序可以查看读取资料之后,是否遭到写入执行的变更,再采取后续的措施(重新读取变更信息,或者抛出异常) ,这一个小小改进,可大幅度提高程序的吞吐量!!
示例代码:

import java.util.concurrent.locks.StampedLock;

public class StampedLockTest {

    private static final StampedLock sl = new StampedLock();
    private static int x;
    private static int y;

    public static void move(int deltax,int deltay) throws InterruptedException{
        System.out.println("写线程----"+Thread.currentThread().getName());
        long sw = sl.writeLock();//获取写锁
        try{
            x = x+deltax;
            y = y+deltay;
        }finally{
            sl.unlockWrite(sw);//释放写锁
        }
    }

    public static int distanceFromOrigin(){
        long sr = sl.tryOptimisticRead(); //获取乐观读锁,不会阻塞写锁
        int currentx = x;
        int currenty = y;
        //读完成后验证期间是否有写操作改变了数据sl.validate(sr)为true则表示期间无写操作,否则表示数据可能已经被改变
        System.out.println(currentx+"---第一次读取数据-----"+currenty);
        if(!sl.validate(sr)){
            sr = sl.readLock(); //使用了悲观锁,会阻塞写锁
            try{
                System.out.println("悲观锁读线程----------"+Thread.currentThread().getName());
                currentx = x;
                currenty = y;
            }finally{
                sl.unlockRead(sr);//释放悲观读锁
            }
        }else{
            System.out.println("乐观锁读线程----------"+Thread.currentThread().getName());
        }
        System.out.println(currentx+"----第二次读取数据----"+currenty);
        return currentx*currenty;
    }
    /** * @param args */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        for(int i=0;i<10;i++){
            final int q =i;
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    try {
                        move(q,q+8);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        for(int i=0;i<50;i++){
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    try {
                        distanceFromOrigin();
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }

}

这里写图片描述


推荐阅读
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 本文介绍如何在Spring Boot项目中集成Redis,并通过具体案例展示其配置和使用方法。包括添加依赖、配置连接信息、自定义序列化方式以及实现仓储接口。 ... [详细]
  • 本文介绍了如何利用Python进行批量图片尺寸调整,包括放大和等比例缩放。文中提供了详细的代码示例,并解释了每个步骤的具体实现方法。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 本文介绍 Java 中如何使用 Year 类的 atMonth 方法将年份和月份组合成 YearMonth 对象,并提供代码示例。 ... [详细]
  • 深入解析动态代理模式:23种设计模式之三
    在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。 ... [详细]
  • 深入解析ArrayList与LinkedList的差异
    本文详细对比了Java中ArrayList和LinkedList两种常用集合类的特性、性能及适用场景,通过代码示例进行测试,并结合实际应用场景分析其优缺点。 ... [详细]
  • 本文深入探讨了 Java 中 LocalTime 类的 isSupported() 方法,包括其功能、语法和使用示例。通过具体的代码片段,帮助读者理解如何检查特定的时间字段或单位是否被 LocalTime 类支持。 ... [详细]
  • 本文详细探讨了Android Activity中View的绘制流程和动画机制,包括Activity的生命周期、View的测量、布局和绘制过程以及动画对View的影响。通过实验验证,澄清了一些常见的误解,并提供了代码示例和执行结果。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 本文将探讨2015年RCTF竞赛中的一道PWN题目——shaxian,重点分析其利用Fastbin和堆溢出的技巧。通过详细解析代码流程和漏洞利用过程,帮助读者理解此类题目的破解方法。 ... [详细]
  • Python + Pytest 接口自动化测试中 Token 关联登录的实现方法
    本文将深入探讨 Python 和 Pytest 在接口自动化测试中如何实现 Token 关联登录,内容详尽、逻辑清晰,旨在帮助读者掌握这一关键技能。 ... [详细]
  • Python 工具推荐 | PyHubWeekly 第二十一期:提升命令行体验的五大工具
    本期 PyHubWeekly 为大家精选了 GitHub 上五个优秀的 Python 工具,涵盖金融数据可视化、终端美化、国际化支持、图像增强和远程 Shell 环境配置。欢迎关注并参与项目。 ... [详细]
author-avatar
张雍昊
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有