概述

  为了对共享资源提供更细粒度的同步控制,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. 《剑指offer》— JavaScript(30)连续子数组的最大和

    连续子数组的最大和 题目描述 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好 ...

  2. Saltstack-API(十二)

    Saltstack-API 官方文档 https://docs.saltstack.com/en/latest/ref/netapi/all/salt.netapi.rest_cherrypy.htm ...

  3. LaTeX字体设置

    % 导言区 % 帮助文档 texdoc lshort-zh % 设置normalsize大小 \documentclass[10pt]{ctexart} %article,ctexbook封面, ct ...

  4. javascript类式继承函数最优版

    直接上代码: klass函数 var klass = function (Parent, props) { var Child, F, i; //1.新构造函数 Child = function () ...

  5. 20155306 2016-2017-2 《Java程序设计》第八周学习总结

    20155306 2016-2017-2 <Java程序设计>第八周学习总结 教材学习内容总结 第十五章 通用API 15.1 日志 java.util.loggging包提供了日志功能相 ...

  6. HDU 1728 逃离迷宫 BFS题

    题目描述:输入一个m*n的地图,地图上有两种点,一种是 . 表示这个点是空地,是可以走的,另一种是 * ,表示是墙,是不能走的,然后输入一个起点和一个终点,另外有一个k输入,现在要你确定能否在转k次弯 ...

  7. Docker01 CentOS配置Docker

    Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是完全使用沙箱机制,相互之间不会有任何 ...

  8. ZYNQ. DMA基本用法

    DMA环路测试 vivadoblock zynq7 + dma +fifo sdk 中可以导入 demo demo 中 默认都是 一个字节8bit数据 的测试程序. 如果是其他长度的数据,不仅要修改数 ...

  9. vs-code 配置

    vs-code 快键键 命令面板 ctrl+shift+p vs-code 相关插件 AutoFileName Chinese (Simplified) Language Pack for Visua ...

  10. decimal模块

    简介 decimal意思为十进制,这个模块提供了十进制浮点运算支持. 常用方法 1.可以传递给Decimal整型或者字符串参数,但不能是浮点数据,因为浮点数据本身就不准确. 2.要从浮点数据转换为De ...