美文网首页
Java多线程并发之java.util.concurrent包实

Java多线程并发之java.util.concurrent包实

作者: 魂之挽歌w | 来源:发表于2019-09-28 22:41 被阅读0次

    前言

      Java开发中我们往往会使用到syconchornize、volitaile等锁机制,然而,对于实际编程来说,应该尽可能远离底层结构。java1.5新引入的了java.util.concurrent包,提供了一系列专门处理并发的类,可以让开发者更方便、更安全地解决并发问题,今天来学习一下java.util.concurrent包的实现机理。

    不同系统的并发机制

    • UNIX:管道、消息、共享内存、信号量、信号
    • Linux内核:原子操作、自旋锁、信号量、屏障(由于服务器一般都位于Linux服务器上,因此此是我们最重要要了解的)
    • Solaris线程同步原语:互斥锁、信号量、多读者/单写者锁、条件变量
    • Windows:等待函数、分派器对象、临界区、轻量级读写锁和条件变量

    互斥的需求

    • 强制互斥: 当临界区共享时,一次只允许一个线程进入临界区,即必须强制实施互斥
    • 禁止干涉: 一个在非临界区停止的线程不能干涉其他线程,包括临界区和非临界区的线程
    • 禁止无限延迟: 决不允许出现需要访问临界区的线程被无限延迟的情况,如产生死锁或饥饿
    • 可用立入: 当没有线程在临界区中时,任何需要进入临界区的线程必须能够立即进入
    • 核数无关: 对相关线程的执行速度和处理器的数目没有任何要求和限制
    • 有限时间: 一个线程驻留在临界区的时间必须是有限的

    互斥的方案

    • 硬件支持:处理器原生支持的互斥指令,好处是可以减少开销,但很难成为一个通用的解决方案
    • 系统或语言级别支持:即由操作系统或程序语言提供该级别的互斥支持,比如信号量、管程、消息传递等
    • 软件方法支持:这些方法通常基于在访问内存时基本互斥的假设,尽管允许访问的顺序事先没有具体安排,但同时访问内存中的同一地址的操作被内存仲裁器串行化执行了,即可以理解用算法的方式解决互斥问题,比如Dekker算法、Peterson算法

    消息传递

    1. 消息传递的概述
      消息定义:消息传递指的是线程间通过发送消息的方式实现相互通信
      消息实现:通常会提供一对原语实现 send(destination,message) 、receive(source,message)
      发送消息:一个线程以消息massage的形式给另一个指定的目标destination线程发送消息
      接收消息:线程通过执行recieve原语接收来自源线程source的消息massage
    2. 消息结构
      消息类型: 指定的消息类型,接收者往往会根据该类型进行消息监听和捕获
      目标ID/源ID: 发送方/源的标识符
      消息长度: 整个消息的总长度,注意要控制长度
      控制信息: 额外信息,比如创建消息链表的指针、记录源和目标之间传递消息数目、顺序和序号以及优先级
      消息内容: 消息正文,相当于Body
      补充: 读者可以参间ISO中各种协议的包格式,比如HTTP和TCP的包
      3.消息通信情况
      send:要么发送线程被阻塞直到该消息被目标线程接收,要么不阻塞
      receive :
      若消息在接收之前已经被发送,该消息被目标线程接受并继续执行
      若没有正在等待的消息,则该目标线程被阻塞直到所等待的消息到达,或者该线程继续执行,放弃接收


      消息通信情况

    Couurent包结构

    Couurent包结构

    Concurrent 包整体类图

    Concurrent 包整体类图

    Concurrent包实现机制

    • 综述: 在整个并发包设计上,Doug Lea大师采用了3.1 Concurrent包整体架构的三层结构
    1. 底层-硬件指令支持
    • 综述: 并发包最底层是依赖于硬件级别的Volatile和CAS的支持
    • Volatile:借用 Volatile 的内存读写语义和阻止重排序保证数据可见性
    • CAS: 借用CAS的高效机器级别原子指令保证内存执行的 读-改-写 操作的原子性
    • 组合: 借用 Volatile 变量的读/写和CAS实现线程之间的有效通信,保证了原子性、可见性、有序性
    1. 中间层-基础数据结构+算法支持
    • 综述: 在数据结构和算法的设计使用上,Doug Lea大师专门设计了AQS框架作为所有并发类库的并发基础,同时引入非阻塞算法和原子变量类增强了并发特性
    • AQS框架: AQS中提供了最基本、有效的并发API, Doug Lea大师期望其作为所有并发操作的基础解决方案,并发包中的绝大部分实现都是依赖于AQS(AbstractQueuedSynchronizer),同时 AQS的基础是 CAS 和 Volatile的底层支持
    • 非阻塞数据结构: 非阻塞数据结构是非阻塞队列的设计基础,同时也是阻塞队列的参考对比的重要依据
    • 原子变量类: Doug Lea大师专门为所有的原子变量设计了专门的类库,甚至在后期还对齐做了增强,比如 LongAdder、LongAccumulator 等,从侧面可以反映出数值操作对于编程的重要性
    1. 高层-并发类库支持
    • 综述: Doug Lea大师在并发包中已经提供了丰富的并发类库极大方便了快速、安全的使用并发操作
    • Lock: Lock接口定义了一系列并发操作标准,详情参见 AQS框架之Lock
    • 同步器: 每个并发类的同步器的实现依赖于AQS(继承),比如 ReentrantLock 中的Sync;同时笔者也将 并发类 同属于同步器的范围内
    • 阻塞队列: 顾名思义,支持阻塞的队列,主要是以Queue结尾的类
    • 执行器: 所谓执行器,指的是任务的执行者,比如线程池和Fork-Join
    • 并发容器: 即支持并发的容器,主要包含COW和以Concurrent开头的类,通常并发容器是非阻塞的

    参考:

    相关文章

      网友评论

          本文标题:Java多线程并发之java.util.concurrent包实

          本文链接:https://www.haomeiwen.com/subject/melluctx.html