`
孤烟客
  • 浏览: 10027 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java同步器框架剖析

阅读更多

Java同步器框架剖析

         同步器(Synchronizer)框架是java并发的核心基础,充分理解其设计原理能够更精准的使用/扩展部分工具,进而提高应用程序的性能。本文的分析依托源码,纯属个人见解。希望阅读者能够批判阅读。

         闲话少说,我们直接来说AbstractQueuedSynchronizer类,这个是同步器框架的核心类。它的实现思路:1,用volatile+原子操作来维护同步状态,2,如果锁获取失败将需要排队,3,通过LockSupport进行线程阻塞/唤醒操作。

我们先来看一下同步器的结构图,然后针对每个步骤进行逐一分析。

 

如图,我们很容易将此图转化成uml类图,我们也能够看出这是模板方法设计模式,AbstractQueuedSynchronizer把锁的获取/释放交给子类去处理。它本身所处理的问题是一旦获取失败/取消成功以后需要怎么做。

         我们从ReetrantLock锁开始根据调用过程来分析一次锁获取过程:当我们执行了lock.lock();意味着我们直接调用了AbstractQueuedSynchronizeracquire方法。Acquire的代码如下:

1tryAcquire方法,这个是子类方法,上文提到了,子类负责锁的获取,框架本身负责失败后的处理。如果1成功,直接返回了,如果1失败,转2

2addWaiter方法,这个方法的核心目标是将操作失败的线程添加到队列的尾部。我通过图来简单解释一下这个队列,因为他跟我们常规所认识的队列概念有些出入。根据注释可知这个是CLH queue队列的改进版,不过这些概念已经不重要了,主要是我们通过自己的分析能完全理解它的设计思路。

 

我们把这个大框看做是AbstractQueuedSynchronizer类,Headtail是其中两个属性,同时他们分别又指向了队列的头部跟尾部,队列在插入的时候从尾部添加,删除的时候从头部移除。

假设当前的内存如上图所示,这时候调用了addWaiter方法操作过程如下

A直接将新增节点添加到链表尾部,

B将尾部节点的引用指向新增节点

通过以上两个步骤完成了线程的排队,代码如下:

 这里需要解释两点:1,对于尾部更新compareAndSetTail(pred, node)是采用了原子操作。因为是原子操作,所以无论此时有多少线程并发执行该方法,只有一个能够执行成功,其他线程将进入enq方法循环尝试,直到更新成功为止。这里的实现思路是典型的乐观锁形式,相比于线程切换,让cpu多尝试几次往往会大大提供程序的伸缩性,如果你的应用因为太多的阻塞/线程频繁调度而烦恼,不妨试试这种方法。2,这种非常规的数据结构有什么好处么?首先是将插入和删除分开,从而减少了访问热点。其次相对来说比较容易找到需要唤醒的节点。

3acquireQueued 方法,这个方法不太好理解。,简单来说他主要做了两件事儿。A阻塞当前线程。B一旦有线程唤醒该线程,尝试重新获得锁。

以下是这段代码的核心部分:

  for (;;) {

                                    

                final Node p = node.predecessor();

               //如果前置队列是头结点并且获取锁成功,

if (p == head && tryAcquire(arg)) {//a

                    setHead(node);

                    p.next = null; // help GC

                    failed = false;

                    return interrupted;

                }

                if (shouldParkAfterFailedAcquire(p, node) &&

                    parkAndCheckInterrupt())//b

                    interrupted = true;

            }

假设当前线程执行的情况是2中添加第四个节点的情况,那么程序将直接执行b操作部分。
b
操作的核心就是阻塞当前线程,更具体的是通过LockSupport类的park方法来实现的。如果你想了解LockSupport到底是怎么实现阻塞的,那么抱歉了,jdk中并没有提供其实现源码。本质上,他也不是jdk能够实现得了的。Java的线程原生的映射到了操作系统的轻量级进程,能够直接阻塞操作系统进程的,恐怕只有操作系统提供的系统调用了。我们可以简单的把它理解为 java调用操作的系统的一个包装。至此,一个获取锁的操作在获取失败后完全阻塞了。

         程序走到此似乎已经到了尽头了,也的确如此,如果没有人来叫醒他,他将长睡不起。但是分析还得继续才行,假设此时有线程执行完调用了release方法,release的实现思路非常简单,如果当前线程释放成功,就用LockSupport唤醒最前头的线程节点。假设Nd4节点之前的节点都已经执行完了,那么回到当前线程,他从b操作醒来,继续执行,从而回到a操作,有一个小注意点是头节点是空节点,从第二个起才会存储真正阻塞的线程,所以有了node.predecessor()操作。注意:此处当前线程要重新调用tryAcquire重新竞争,运气不好他会失败继续阻塞的,这也是非公平锁的实现核心。

         至此,同步框架的分析接近尾声了,缪缪几行代码,但是完全理解起来并没有吃点甜点来的轻松。回顾一下1,他通过模板方法设计模式构造整个架构,我们可以通过继承来灵活的扩展适合我们的同步工具。2,他通过volatile+原子操作的int变量来维护锁状态。可以说原子操作和volatile的结合构成了整个并发框架的基础。Volatile是很早就出现在我们视野中的修饰词,但是一直抑郁不得志,因为单纯的可见性并无法解决并发问题。单纯的原子操作也无非只是一个计算机指令,他可以保证同时只有一个操作成功,但是没法保证更新后对其他线程立刻可见,java的线程模型有时候也是很蛋疼的东西。只有把这两个东西结合在一起,这让我想起了‘金风玉露一相逢’的诗句,算了,这个扯的有点多了。3,他用了一个变形的双向链表结构进行线程排队,优点已经说过了,好的数据结构我们可以借鉴。4,他是通过LockSupport系统工具来完成线程阻塞,唤醒的。5,他设计的精巧之处就是抢占式思维,这是他能够提供性能的主要手段之一。

 

  • 大小: 9.8 KB
  • 大小: 25.6 KB
  • 大小: 7.7 KB
  • 大小: 9.1 KB
  • 大小: 29.4 KB
分享到:
评论

相关推荐

    高性能的java AIO通信框架 物联网参考

    - **性能优化**:监控和分析系统的运行情况,持续优化性能,例如减少内存拷贝、避免过度同步等。 本压缩包中的"smart-socket"可能是一个实现了以上特性的Java AIO通信框架源码,开发者可以通过阅读和学习,理解如何...

    30种java技术框架图

    ### Java技术框架图知识点概述 #### 1. Java类加载器架构 Java 类加载器是 Java 虚拟机(JVM)的一个关键组件,负责在程序运行时动态地加载类和接口。它按照一定的顺序加载类,并确保每个类只被加载一次。Java 类加载...

    java集合框架系统剖析

    ### Java集合框架系统剖析 #### 一、Java集合框架概览 Java集合框架是一个高度抽象化的数据结构模型,它提供了一系列标准的接口、抽象类以及具体的实现类来帮助开发者高效地管理和操作各种对象集合。这一框架是...

    java框架源码分析java框架源码分析

    Java框架源码分析是软件开发领域中的重要环节,它能帮助开发者深入理解框架的工作原理,提升编程技巧,优化代码质量,以及解决实际开发中的问题。本文将围绕Java框架的源码分析进行详细探讨。 首先,Java框架是为...

    史上最强的java面试题 corejava javaWeb SSH框架

    最后,Java的经典案例分析能帮助我们更好地理解实际开发中遇到的问题和解决方案。这些案例可能涵盖设计模式、并发控制、网络通信等方面,通过实际代码示例来提升我们的编程能力。 总之,掌握Java核心、Java Web和...

    30种java技术框架

    ### 30种Java技术框架概述 #### 一、Java类加载器架构 Java类加载器是Java虚拟机(JVM)的重要组成部分之一,主要负责在程序运行时将类文件加载到内存中,并对其进行验证、准备和解析等初始化操作。类加载器采用双亲...

    基于Java框架开发的WMS管理系统+完整源码+数据库备份

    【Java框架开发的WMS管理系统】是现代企业信息化管理中的重要组成部分,主要用于仓库管理的高效化、自动化。WMS(Warehouse Management System)系统利用先进的信息技术,实现库存的精确跟踪,优化仓库作业流程,...

    Java 常用数据结构分析

    以下是对这些数据结构及其在Java中的具体实现的详细分析: 1. **线性表**: - **ArrayList**: 作为线性表的一种实现,ArrayList是一个动态数组,它允许快速的随机访问(O(1)时间复杂度)。通过索引可以快速获取...

    Java并发编程:深入解析抽象队列同步器(AQS)及其在Lock中的应用

    AQS通过内部类Sync映射所有同步器调用,维护资源状态的可用性最后,文档提供了AQS源码的初步分析,突出了其设计和实现的关键部分,如等待队列节点类Node的定义综合来看,文章为Java开发者提供了对AQS及其在...

    java中Collection深入剖析

    本篇文章将深入剖析Java中的`Collection`框架,探讨其核心概念、主要接口及其实现类,以及在实际开发中如何有效地使用这些工具。 首先,我们来看`Collection`接口。它定义了集合的基本操作,如添加元素(`add()`)...

    java集合框架全面进阶

    5. **源码分析**:深入理解Java集合框架的源码,有助于优化代码性能。例如,了解HashMap的扩容机制、LinkedList的节点操作、ArrayList的动态数组管理等,能够帮助开发者在设计和实现自己的数据结构时避免常见陷阱。 ...

    若以框架源码 很好用的java框架

    "若以框架"是一个在Java开发领域中被提及的框架,根据标题和描述,我们可以推断这是一款受到好评且适用于Java开发的框架,提供源代码供开发者学习和使用。源码对于开发者来说是非常宝贵的资源,它能帮助我们深入理解...

    基于java的brap(Java远程调用框架 BRAP).zip

    Java远程调用框架BRAP(Business Remote Access Protocol)是一种高效、灵活且可扩展的解决方案,专为解决分布式系统中的远程服务调用问题而设计。它提供了高性能、低延迟的通信机制,使得Java应用能够轻松地跨越...

    30种java技术框架-方案架构图汇总.zip

    1. **Spring**:Spring 是一个全面的Java企业级应用开发框架,提供依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,广泛用于构建Web应用和服务。 2. **Spring Boot**:基于Spring的简化版启动框架...

    基于Java的SSM框架高校科研系统设计源码

    SSM框架,全称为Spring、SpringMVC和MyBatis的组合,是Java Web开发中常用的三大组件。这个"基于Java的SSM框架高校科研系统设计源码"提供了一个全面的解决方案,旨在帮助高校科研团队高效地管理和协作科研项目。 ...

    JAVA基础,框架知识,WEB知识,数据库知识面试题.

    在IT行业中,尤其是在Java开发领域,掌握扎实的基础知识、熟悉常用框架、理解Web技术以及对数据库的深入理解是至关重要的。以下将详细阐述这些领域的关键知识点: **Java基础:** Java是一门面向对象的编程语言,其...

    java网络框架对比报告.pdf

    本报告旨在对比分析两大主流Java网络框架——Apache Mina与JBoss Netty,从功能特性、使用便捷性、性能等方面进行深入探讨。 #### 二、Apache Mina网络通信应用框架 ##### 2.1 概述 Apache Mina是一个基于Java NIO...

    java开源包8

    Spring4GWT ...JARP是为petri 网提供的一个Java编辑器,基于ARP分析器。可以将网络图导出为 GIF, JPEG, PNG, PPM, ARP and PNML (XML based)文件格式。使用了优秀的JHotDraw 5.2 框架。 activemq...

    一种Java日志系统框架的设计与实现 转).doc

    本文将探讨一种基于Java的日志系统框架的设计与实现,该框架结合了日志服务的两种主要形式,即服务进程和系统调用,并通过Java线程技术提供同步日志发送、快速记录以及灵活的格式配置和过滤机制。 首先,日志系统...

    java学习笔记基础和框架

    Java学习笔记基础与框架 Java是一种广泛使用的面向对象的编程语言,它的设计目标是具有简单性、面向对象、健壮性、安全性、可移植性等特点。这份“java学习笔记基础和框架”涵盖了从Java的基础概念到高级特性的全...

Global site tag (gtag.js) - Google Analytics