java多线程编程

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

2018-04-19  本文已影响0人  李2牛
线程同步机制 是一套用于协调线程之间的数据访问和活动的机制

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



1. 相关概念术语:

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

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

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

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

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

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

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


2. 锁的划分

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


3. 锁的实现

显式锁的使用

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

内部锁的调度

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

显式锁的使用

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

显式锁的调度

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

上一篇下一篇

猜你喜欢

热点阅读