Java多线程编程-线程同步机制

线程同步机制 是一套用于协调线程之间的数据访问和活动的机制

java提供的线程同步有:锁,volatile关键字,final关键字,static 关键字以及一些相关API;



1. 相关概念术语:

线程访问共享数据之前必须申请相应的锁,线程的这个操作叫做锁的获得(Acquire)

一个线程获得某个锁,该线程就称为相应锁的持有线程,一个锁一次只能被一个 线程持有。锁的持有线程可以对该锁所保护的共享数据进行访问,访问结束后线程必须释放(Release)相应的锁。

锁的持有线程在获得锁之后和释放锁之前的这段时间所执行的代码称为临界区(Critical Section),共享数据只允许再临界区进行访问,临界区一次只能被一个线程执行。

如果多个线程访问同一个锁保护的共享数据那么我们就称这些线程同步在这个锁上,这些线程执行的临界区叫做锁所引导的临界区

可重入性,一个线程在其持有一个锁时还能继续成功申请该锁,就称该锁为可重入锁。

锁的争用,Java平台中的锁的调度策略包括公平策略和非公平策略,相应的锁就有公平锁和非公平锁。内部锁为公平锁,显式锁既支持公平锁又支持非公平锁。

锁的粒度表示的是共享数据的量的大小


2. 锁的划分

JVM对锁的实现方式进行了划分。

  • 内部锁(Intrinsic Lock):通过synchronized 实现
  • 显式锁(Explicit Lock): 通过java.concurrent.locks.Lock接口的实现类实现。

3. 锁的实现

  • 内部锁:synchronized 关键字
    Java平台任何一个对象都有一个唯一与之相关的锁。这种锁被称为监视器(Monitor)或者内部锁(Intrinsic Lock)。内部锁是一种排他锁。可以保证原子性,可见性和有序性。
显式锁的使用

内部锁是使用 synchronized 关键字实现的。
synchronized 修饰的方法就被称为同步方法,
synchronized 关键字修饰的静态方法就被称为同步静态方法
synchronized 修饰的实例方法就被称为同步实例方法,
synchronized关键字修饰的代码块称为同步块(synchronized block)
线程在执行临界区代码时必须持有该临界区的引导锁,一个线程执行到同步代码块时必须先申请该同步块的引导锁。只有申请成功获得该锁的线程才能够执行相应的临界区。一个线程执行完临界区代码后引导该临界区的锁就会自动释放,在这个过程中线程锁对内部锁的申请与释放动作由 Java 虚拟机负责代为实施,因此 synchronized 实现的锁叫做内部锁。

内部锁的调度

java 会为每个内部锁分配一个入口集(Entry Set),用于记录等待获得内部锁的线程。多个线程申请同一个锁的时候只有一个申请者可以成为该锁的持有线程(即申请锁的操作成功),而其他申请者的申请操作会失败。失败的线程不会立刻抛出异常而是会被暂停(生命周期的状态变为BLOCKED)并被从存入相应的入口集中等待再次申请锁的机会。入口集中的线程就被称为相应内部锁的等待线程。当线程申请的锁被持有线程释放的时候,锁的入口集中的任意一个线程会被虚拟机唤醒,从而得到再次申请锁的机会。由于java虚拟机对内部锁调度仅支持非公平调度,被唤醒的等待线程占用处理器运行时可能还有其他的新的活跃线程(处于 RUNNABLE 状态,而且未进入过入口集)与该线程抢占这个被释放锁,因此被唤醒的线程不一定能称为该锁的持有线程。此外java选择的入口集中的线程作为锁的下次持有线程,可能是入口集中等待时间最长的也可能是等待时间最短的线程,这个细节与java虚拟机具体实现有关。

  • 显式锁:Lock 接口(Since JDK 1.5)
    显式锁是一种排他锁,作为一种线程同步机制,其作用和内部锁相同,但是具有一些内部锁不具有的特性,不是内部锁的替代品
    显式锁 ( Explicit Lock ) 是java.util.concurrent.lcoks.Lock 接口的实例。
显式锁的使用

创建 Lock 接口的实例
访问共享数据前申请相应的显式锁
临界区内访问共享数据
共享数据结束后释放锁

显式锁的调度

ReentrantLock 既支持公平锁也支持非公平锁。使用ReentrantLock 的一个构造器参数指定。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.解决信号量丢失和假唤醒 public class MyWaitNotify3{ MonitorObject m...
    Q罗阅读 922评论 0 1
  • Java-Review-Note——4.多线程 标签: JavaStudy PS:本来是分开三篇的,后来想想还是整...
    coder_pig阅读 1,690评论 2 17
  • 在开发Java多线程应用程序中,各个线程之间由于要共享资源,必须用到锁机制。Java提供了多种多线程锁机制的实现方...
    千淘萬漉阅读 6,973评论 1 33
  • 我有个七岁的女儿。在她更小一点儿时,我感冒发烧,躺在床上不能起来,她就会倒好水端到我床前,盯着我吃药,像个小大人一...
    荒岛黎明7809阅读 304评论 0 0
  • 第一题,金融资产的主要估值方法 答案1: 现金流贴现模型(使用收入的资本化定价方法来决定普通股股票的内在价值的)市...
    纪疯癫阅读 475评论 0 1