概述

  为了对共享资源提供更细粒度的同步控制,JDK5新增了java.util.concurrent(JUC)并发工具包,并发包新增了Lock接口(以及相关实现类)用来实现锁功能,它提供了与synchronized关键字相似的同步功能,只是在使用时需要显式地获取和释放锁,还具备内置锁不具备的自由操作锁获取和释放、可中断地获取锁以及超时获取锁等多种synchronized关键字不具备的同步特性。
  为了实现JUC提出的各种功能的锁,JUC包的作者,并发大师Doug Lee提出了同步器 synchronizer的概念,在同步器中定义了共享资源的同步状态,维护了一个双端的先入先出的同步队列用于存放获取共享资源失败而等待的线程,线程利用同步器实现的锁获取共享资源流程如下:

为了实现上述操作,需要下面三个基本组件的相互协作:

  • 对共享资源同步状态进行原子性管理 ---> 利用CAS对同步状态进行更新
  • 线程的阻塞与唤醒 ---> 调用native方法
  • 等待队列的管理 ---> 维护FIFO队列

  由此可以看出,同步器是实现锁的关键,同步器面向的是线程访问和资源控制,它定义了线程对资源是否能够获取以及线程的排队等操作。关于同步器的详细解释会在AQS(AbstractQueuedSynchronizer)解析里给出。

JUC锁框架图

  JUC中Lock接口定义了锁的规范,各种功能的锁都实现了Lock接口,各个锁以内部类继承AQS同步器的方式聚合了同步器,从而以同步器为基石实现具体功能的锁。

  1. Lock
      Lock接口为独占锁(同一时间共享资源只能由一个线程获取),共享锁(同一时间共享资源可由多个线程获取),公平锁(各个线程获得锁的机会是公平的),非公平锁(各个线程获得锁的机会是公平的),重入锁(线程在获取到锁之后,再次获取该锁而不会被该锁所阻塞,不会自己把自己锁在外面)提供了实现规范,接口中定义的方法如下:

  2. AbstractQueuedSynchronizer
      AbstractQueuedSynchronizer就是被称之为AQS的类,可以用于构建锁或者其他相关同步装置的基础框架。从图中也可以看出,ReentrantLock,ReentrantReadWriteLock,CountDownLatch,CyclicBarrier和Semaphore这些类通过内部类继承AQS的方式来实现锁的功能。

  3. Condition
      Condition需要和Lock联合使用,它的作用是代替Object监视器方法,可以通过await(),signal()来休眠/唤醒线程。Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用 Object.wait 访问的隐式监视器类似,但提供了更强大的功能,接口中定义的方法如下:

  4. LockSurport
      LockSupport中的park() 和 unpark()调用native方法将线程休眠。

  5. ReentrantLock
      ReentrantLock对与共享资源采取的是较为保守的独占策略,即只有一个线程能够获得锁;ReentrantLock支持公平锁和非公平锁,默认是非公平锁;从名称也能看出,ReentrantLock是可重入锁。

  6. ReentrantReadWriteLock
      ReentrantReadWriteLock是读写锁接口ReadWriteLock的实现类,它包括子类ReadLock和WriteLock。ReentrantLock是共享锁,而WriteLock是独占锁。

  7. CountDownLatch
      CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

  8. CyclicBarrier
      CyclicBarrier是一个同步辅助类,允许一组线程互相等待,直到到达某个公共屏障点(common barrier point)。因为该barrier在释放等待线程后可以重用,所以称它为循环的barrier。

  9. Semaphore
      Semaphore是一个计数信号量,它的本质是一个"共享锁"。信号量维护了一个信号量许可集。线程可以通过调用acquire()来获取信号量的许可;当信号量中有可用的许可时,线程能获取该许可;否则线程必须等待,直到有可用的许可为止。 线程可以通过release()来释放它所持有的信号量许可。

使用内置锁还是JUC显示锁?

  JUC中的显示锁提供了与synchronized内置锁相同的互斥性与内存可见性,那么我们的多线程代码到底使用哪一种锁来实现同步呢?首先从性能角度考虑,在JDK5 显示锁刚推出时,性能是大幅领先于内置锁的,在随后的JDK版本中,JVM对内置锁进行了性能优化,现在二者的性能已经没有明显优劣之分;从功能使用上,内置锁的使用较为简单,无需手动获得以及释放锁,而显示锁的功能更为强大,具有更高的灵活性,当我们需要使用到锁的高级功能,如以响应中断/支持超时的方式获取锁或者自定义实现锁,这时候可以考虑内置锁。

多线程学习笔记二之JUC组件的更多相关文章

  1. 多线程学习笔记(二) BackgroundWorker 和 ProgressChanged

    BackgroundWorker是在内部使用了线程池的技术:同时,在Winform 或WPF编码中,它还给工作线程和UI线程提供了交互的能力. Thread和ThreadPool默认都没有提供这种交互 ...

  2. java多线程学习笔记——详细

    一.线程类  1.新建状态(New):新创建了一个线程对象.        2.就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中, ...

  3. amazeui学习笔记二(进阶开发5)--Web 组件开发规范Rules

    amazeui学习笔记二(进阶开发5)--Web 组件开发规范Rules 一.总结 1.见名知意:见那些class名字知意,见函数名知意,见文件名知意 例如(HISTORY.md Web 组件更新历史 ...

  4. amazeui学习笔记二(进阶开发2)--Web组件简介Web Component

    amazeui学习笔记二(进阶开发2)--Web组件简介Web Component 一.总结 1.amaze ui:amaze ui是一个web 组件, 由模板(hbs).样式(LESS).交互(JS ...

  5. C#学习笔记——面向对象、面向组件以及类型基础

    C#学习笔记——面向对象.面向组件以及类型基础 目录 一 面向对象与面向组件 二 基元类型与 new 操作 三 值类型与引用类型 四 类型转换 五 相等性与同一性 六 对象哈希码 一 面向对象与面向组 ...

  6. muduo学习笔记(二)Reactor关键结构

    目录 muduo学习笔记(二)Reactor关键结构 Reactor简述 什么是Reactor Reactor模型的优缺点 poll简述 poll使用样例 muduo Reactor关键结构 Chan ...

  7. java之jvm学习笔记二(类装载器的体系结构)

    java的class只在需要的时候才内转载入内存,并由java虚拟机的执行引擎来执行,而执行引擎从总的来说主要的执行方式分为四种, 第一种,一次性解释代码,也就是当字节码转载到内存后,每次需要都会重新 ...

  8. JAVA多线程学习笔记(1)

    JAVA多线程学习笔记(1) 由于笔者使用markdown格式书写,后续copy到blog可能存在格式不美观的问题,本文的.mk文件已经上传到个人的github,会进行同步更新.github传送门 一 ...

  9. java进阶-多线程学习笔记

    多线程学习笔记 1.什么是线程 操作系统中 打开一个程序就是一个进程 一个进程可以创建多个线程 现在系统中 系统调度的最小单元是线程 2.多线程有什么用? 发挥多核CPU的优势 如果使用多线程 将计算 ...

随机推荐

  1. linux command ------ unlink 和 rm 的区别

    unlink 不能用于删除文件夹,rm 可以删除文件和文件夹 当删除文件时,rm 和 unlink 是完全一样的.

  2. Vue模板语法V-bind

    一.插值 1.文本 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://w ...

  3. swift3.0之后的Error处理

    在之前的版本中,Swift中Error与OC中NSError没有关系.但是现在两者可以互相强转. 我们看看两者的区别:Error是一个实现Error协议的枚举或者结构体,对外能够获取的具体信息只有ra ...

  4. 【译】使用OpenVAS 9进行漏洞扫描

    本文译自Vulnerability Scanning with OpenVAS 9 part 1: Installation & Setup系列,本文将融合目前已经发表的四个部分. Part ...

  5. 20165230 《Java程序设计》实验五《网络编程与安全》实验报告

    20165230 <Java程序设计>实验五<网络编程与安全>实验报告 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:田坤烨 学号:20165230 成绩: ...

  6. 搭建RabbitMQ集群(通用)

    RabbitMQ在Erlang node(节点)上 Erlang天生具有集群特性,非常好搭建集群,每一个节点(node)上具有一个叫erlang.Cookie的东西,也是一个标识符,可以互认. 1). ...

  7. mysql主键的缺少导致备库hang

    最近线上频繁的出现slave延时的情况,经排查发现为用户在删除数据的时候,由于表主键的主键的缺少,同时删除条件没有索引,或或者删除的条件过滤性极差,导致slave出现hang住,严重的影响了生产环境的 ...

  8. Daemon函数的用法

    Daemon函数的用法 说明: 让一个程序后台运行. 原型: #include <unistd.h> int daemon(int nochdir, int noclose); #incl ...

  9. 让linux中 history显示每条命令的操作时间及操作用户【转】

    一.history 中显示日期时间用户名的办法 history 命令,用来显示命令行上的操作记录 不过默认是仅显示操作命令行本身,而没有记录操作时间等细节 例如 这样,我们查找记录时很麻烦,想回顾下某 ...

  10. MySQL多源复制【转】

    什么是多源复制? 首先,我们需要清楚 multi-master 与multi-source 复制不是一样的. Multi-Master 复制通常是环形复制, 你可以在任意主机上将数据复制给其他主机. ...