Lock接口和ReadWriteLock接口
ReentrantLock实现了Lock接口。ReentrantLock是可重入锁,支持同一个线程对资源的重复加锁。
简单用法示例:
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
System.out.println("执行业务操作");
} finally {
lock.unlock();
}
}
ReentrantLock有3个静态内部类:Sync、NonfairSync、FairSync,其中Sync是AQS的子类,是抽象类,有一个抽象的void lock()方法。NonfairSync和FairSync都是Sync的子类,前者是非公平实现,后者是公平实现,这两个类均重写了Sync的lock()方法和AQS的tryAcquire(int acquires)方法。
ReentrantLock的lock()方法内部就是调用Sync实例的lock()方法:
假如是默认的非公平实现的话,则会调用NonfairSync的lock()方法,内部实现是先CAS设置state,由0设置成1,如果设置成功,则把当前线程设置为获取独占锁的线程,如果设置失败,则调用acquire(1)。acquire方法是AQS的方法,内部会先调用tryAcquire()方法,tryAcquire也是AQS的方法,但是AQS没有实现,需要具体实现类实现,这里由NonfairSync具体实现。如果tryAcquire方法返回true,则表示线程获取到锁,lock方法返回。如果tryAcquire方法返回false,则会调用addWaiter()方法把当前线程加到同步队列尾部,然后调用acquireQueued()方法,acquireQueued方法内部有个死循环,直到当前线程获取到锁才会跳出循环返回。NonfairSync的tryAcquire方法内部调用Sync的nonfairTryAcquire()方法,实现是先判断当前state的值是否等于0,如果等于0,表示当前锁还没被任何线程获得,则CAS设置state,由0设置成1,如果设置成功,则把当前线程设置为获取独占锁的线程,返回true,否则返回false。如果不等于0,且当前线程就是之前获取到锁的线程,则让state的值加1,返回true。如果当前线程不是之前获取到锁的线程,则返回false。
假如是公平实现的话,则会调用FairSync的lock()方法,lock()方法内部就是调用acquire(1)。还是先调用tryAcquire方法,然后再根据tryAcquire方法的返回值决定是否继续调用addWaiter()方法、acquireQueued()方法。FairSync的tryAcquire方法实现和NonfairSync的tryAcquire方法实现有一点不同,那就是如果state等于0,会先判断在同步队列中当前节点是否有前驱节点,如果有,表示有别的线程比当前线程更早地请求获取锁,为了保证公平性,直接返回false。如果没有,才会去CAS设置state,等等。
tryLock()方法,不管是非公平实现,还是公平实现,逻辑都是一样的。内部就是调用Sync的nonfairTryAcquire()方法,参数是1。先判断当前state值是否等于0,如果等于0,则CAS设置state,由0设置成1,如果设置成功,则把当前线程设为获取独占锁的线程,返回true,否则返回false。如果state值不等于0,则判断获取锁的线程是否是当前线程,如果是,则把state值加1,返回true,否则返回false。
unlock()方法,不管是非公平实现,还是公平实现,逻辑都是一样的。内部就是调用Sync实例的release()方法,参数是1。release()方法是AQS的方法,内部先调用tryRelease()方法,tryRelease()方法也是AQS的方法,但是AQS没有实现,需要具体实现类实现,这里由Sync实现。tryRelease()方法会先判断当前线程是不是获得锁的线程,如果不是的话,会抛IllegalMonitorStateException异常。如果是的话,就把state的值减1,如果state值变为0,则把获取独占锁的线程设置为null,返回true,否则返回false。
ReentrantLock是AQS的独占式实现,Semaphore是AQS的共享式实现。
Semaphore用法示例:
public static void main(String[] args) {
Semaphore semaphore = new Semaphore(2);
try {
semaphore.acquire();
System.out.println("执行业务操作");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
semaphore.release();
}
}
AQS
AQS,队列同步器,简称同步器,是用来构建锁,如ReentrantLock、ReentrantReadWriteLock,或者其他同步组件,如CountDownLatch、Semaphore的基础框架。它使用一个int类型的成员变量表示同步状态,通过内置的先进先出队列完成线程的排队工作。同步器既支持独占式获取同步状态,也支持共享式获取同步状态,因此可实现不同类型的锁和同步组件。如ReentrantLock是独占式锁,CountDownLatch是共享式锁。
同步器的设计基于模板方法模式。在锁或者同步组件中,创建一个静态内部类,继承同步器并重写它的某些方法来管理同步状态,这些方法如果要修改同步状态,需要调用同步器提供的三个final方法:getState()、setState(int newState)和compareAndSetState(int expect, int update)方法来进行操作,这3个方法能保证状态的改变是安全的。锁或者同步组件对外暴露的获取锁、释放锁的方法会调用同步器的模板方法,这些模板方法又会调用我们重写的方法。可以重写的方法有:
boolean tryAcquire(int arg):独占式获取同步状态。
boolean tryRelease(int arg):独占式释放同步状态。
int tryAcquireShared(int arg):共享式获取同步状态。注意,返回值是int类型,不是boolean类型。返回值大于等于0,表示获取成功。否则,表示获取失败。
boolean tryReleaseShared(int arg):共享式释放同步状态。
boolean isHeldExclusively():
Lock接口和ReadWriteLock接口的更多相关文章
- 7.ReadWriteLock接口及其实现ReentrantReadWriteLock
Java并发包的locks包里的锁基本上已经介绍得差不多了,ReentrantLock重入锁是个关键,在清楚的了解了同步器AQS的运行机制后,实际上再分析这些锁就会显得容易得多,这章节主讲另外一个重要 ...
- Java并发ReadWriteLock接口
java.util.concurrent.locks.ReadWriteLock接口允许一次读取多个线程,但一次只能写入一个线程. 读锁 - 如果没有线程锁定ReadWriteLock进行写入,则多线 ...
- ReadWriteLock 接口详解
ReadWriteLock 接口详解 这是本人阅读ReadWriteLock接口源码的注释后,写出的一篇知识分享博客 读写锁的成分是什么? 读锁 Lock readLock(); 只要没有写锁,读锁可 ...
- 转】C#接口-显式接口和隐式接口的实现
[转]C#接口-显式接口和隐式接口的实现 C#中对于接口的实现方式有隐式接口和显式接口两种: 类和接口都能调用到,事实上这就是“隐式接口实现”. 那么“显示接口实现”是神马模样呢? interface ...
- JDBC的使用(二):PreparedStatement接口;ResultSet接口(获取结果集);例题:SQL注入
ResultSet接口:类似于一个临时表,用来暂时存放数据库查询操作所获得的结果集. getInt(), getFloat(), getDate(), getBoolean(), getString( ...
- 比较器:Compare接口与Comparator接口区别与理解
一.实现Compare接口与Comparator接口的类,都是为了对象实例数组排序的方便,因为可以直接调用 java.util.Arrays.sort(对象数组名称),可以自定义排序规则. 不同之处: ...
- 集合中Set接口与Collection接口,常用子类TreeSet,HashSet.
Set接口与List接口的不同之处在于: 不允许有重复的数据. 定义如下: public interface Set<E>extends Collection<E> 主要方法与 ...
- Callable接口、Runable接口、Future接口
1. Callable与Runable区别 Java从发布的第一个版本开始就可以很方便地编写多线程的应用程序,并在设计中引入异步处理.Thread类.Runnable接口和Java内存管理模型使得多线 ...
- 转载-- http接口、api接口、RPC接口、RMI、webservice、Restful等概念
http接口.api接口.RPC接口.RMI.webservice.Restful等概念 收藏 Linux一叶 https://my.oschina.net/heavenly/blog/499661 ...
随机推荐
- hdu5521 Meeting
传送门 题目 Bessie and her friend Elsie decide to have a meeting. However, after Farmer John decorated hi ...
- 一劳永逸搭建android开发环境(android官网reference sample api tutorial全下载)
[摘要]本文简单介绍了android开发环境的搭建,重点介绍了SDK manager和AVD升级问题:并提供了android reference,sample,api,及docs的下载信息. [1]为 ...
- javaScript实现轮播图
一.需求分析 在首页完成对轮播图的效果实现,完成自动切换图片的功能. 二.技术分析 获取元素 document.getElementById(“id 名称”) 事件(onload) 定时操作: set ...
- 使用 create 命令建立数据库v, 并利用sp_helpdb查看数据库文件
create database v on primary (name = v, filename='D:\v.mdf', size=3mb, maxsize=10mb, filegrowth=2mb ...
- 吴裕雄 python 机器学习——等度量映射Isomap降维模型
# -*- coding: utf-8 -*- import numpy as np import matplotlib.pyplot as plt from sklearn import datas ...
- 【Linux】-Ubuntu常用命令吐血整理
前言 刚刚接触Linux操作系统,真的是各种艰难啊,用个什么东西都得从头开始配置,这个时候才明白从头再来是什么滋味了.自己装了数个数十几次的Centos版本的Linux系统,好不容易争气了一次,跑了起 ...
- Java基础之身份证验证
//简约版package test; import java.util.Scanner; public class ID { /** * 匹配算法 : 1) 得到17位身份证号码与下面给出的17位 2 ...
- P3345 [ZJOI2015]幻想乡战略游戏 动态点分治
\(\color{#0066ff}{ 题目描述 }\) 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越 ...
- ghj1222的代码规范
基本上和notepad++的要求一样. 不定期更新. 1.左大括号换行: int main() { return 0; } 可能有些同志(比如大佬cjh)和我的做法不一样 当一个函数很短的时候可以整个 ...
- win10全半角切换
shift+sapce shift+sapce:全半角切换快捷键,编程的时候发现英文是这种状态,就需要用快捷键切换成半角. (查过老是忘记,在这里写一下记住它)