转载:Java Lock机制解读
Java Lock机制解读
1、synchronized
synchronized是Java语言内置的特性,用来实现对资源的同步访问以及用wait和notify来实现线程间通信。如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁。
存在问题:那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。因此我们需要不论程序的代码块执行的如何最终都将锁对象进行释放,方便其他线程的执行。
2、引入Lock
虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,同时为了更好地释放锁,为了更清晰的表达如何加锁和释放锁,从Java5开始提供了一个新的锁对象Lock。
java.util.concurrent.locks包为锁和等待条件提供一个框架的接口和类,结构如下图所示。
(1)Lock和ReadWriteLock是两大锁根接口,Lock代表实现类是ReentrantLock(可重入锁),ReadWriteLock(读写锁)的代表实现类是ReentrantReadWriteLock。
- Lock 接口支持那些语义不同(重入、公平等)的锁规则,可以在非阻塞式结构的上下文(包括 hand-over-hand 和锁重排算法)中使用这些规则。主要的实现是 ReentrantLock。
- ReadWriteLock 接口以类似方式定义了一些读取者可以共享而写入者独占的锁。此包只提供了一个实现,即 ReentrantReadWriteLock,因为它适用于大部分的标准用法上下文。但程序员可以创建自己的、适用于非标准要求的实现。
(2)Condition 接口描述了可能会与锁有关联的条件变量。这些变量在用法上与使用 Object.wait
访问的隐式监视器类似,但提供了更强大的功能。需要特别指出的是,单个 Lock 可能与多个 Condition
对象关联。为了避免兼容性问题,Condition 方法的名称与对应的 Object 版本中的不同。
3、Lock解读
Lock接口有6个方法
// 获取锁
void lock() // 如果当前线程未被中断,则获取锁
void lockInterruptibly() // 返回绑定到此 Lock 实例的新 Condition 实例
Condition newCondition() // 仅在调用时锁为空闲状态才获取该锁
boolean tryLock() // 如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁
boolean tryLock(long time, TimeUnit unit) // 释放锁
void unlock()
其中 lock与 unlock是最常用的方法,分别是获取与释放锁。
【例子1】Lock锁
package demo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class LockThread {
Lock lock = new ReentrantLock();
public void lock(String name) {
// 获取锁
lock.lock();
try {
System.out.println(name + " get the lock");
// 访问此锁保护的资源
} finally {
// 释放锁
lock.unlock();
System.out.println(name + " release the lock");
}
} public static void main(String[] args) {
LockThread lt = new LockThread();
new Thread(() -> lt.lock("A")).start();
new Thread(() -> lt.lock("B")).start();
}
}
从执行结果可以看出,A线程和B线程同时对资源加锁,A线程获取锁之后,B线程只好等待,直到A线程释放锁B线程才获得锁。
总结一下,也就是说Lock提供了比synchronized更多的功能。但是要注意以下几点:
1)synchronized是Java语言的关键字,因此是内置特性,Lock不是Java语言内置的,Lock是一个接口,通过实现类可以实现同步访问。
2)synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中
3)在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态。
4、ReadWriteLock解读
ReadWriteLock 接口只有两个方法:
//返回用于读取操作的锁
Lock readLock()
//返回用于写入操作的锁
Lock writeLock()
ReadWriteLock 维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 writer,读取锁可以由多个 reader 线程同时保持,而写入锁是独占的。
【例子】三个线程同时对一个共享数据进行读写
package demo; import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; class Queue {
//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
private Object data = null; ReadWriteLock lock = new ReentrantReadWriteLock(); // 读数据
public void get() {
// 加读锁
lock.readLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " be ready to read data!");
Thread.sleep((long) (Math.random() * 1000));
System.out.println(Thread.currentThread().getName() + " have read data :" + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放读锁
lock.readLock().unlock();
}
} // 写数据
public void put(Object data) {
// 加写锁
lock.writeLock().lock();
try {
System.out.println(Thread.currentThread().getName() + " be ready to write data!");
Thread.sleep((long) (Math.random() * 1000));
this.data = data;
System.out.println(Thread.currentThread().getName() + " have write data: " + data);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// 释放写锁
lock.writeLock().unlock();
} }
} public class ReadWriteLockDemo {
public static void main(String[] args) {
final Queue queue = new Queue();
//一共启动6个线程,3个读线程,3个写线程
for (int i = 0; i < 3; i++) {
//启动1个读线程
new Thread() {
public void run() {
while (true) {
queue.get();
}
} }.start();
//启动1个写线程
new Thread() {
public void run() {
while (true) {
queue.put(new Random().nextInt(10000));
}
}
}.start();
}
}
}
执行结果
Thread-0 be ready to read data!
Thread-2 be ready to read data!
Thread-4 be ready to read data!
Thread-2 have read data :null
Thread-0 have read data :null
Thread-4 have read data :null
Thread-5 be ready to write data!
Thread-5 have write data: 3872
Thread-1 be ready to write data!
Thread-1 have write data: 4744
Thread-3 be ready to write data!
Thread-3 have write data: 1371
Thread-2 be ready to read data!
Thread-0 be ready to read data!
Thread-4 be ready to read data!
Thread-2 have read data :1371
Thread-0 have read data :1371
Thread-4 have read data :1371
Thread-5 be ready to write data!
Thread-5 have write data: 2874
Thread-5 be ready to write data!
Thread-5 have write data: 389
Thread-5 be ready to write data!
Thread-5 have write data: 2512
Thread-5 be ready to write data!
Thread-5 have write data: 7455
Thread-5 be ready to write data!
Thread-5 have write data: 5141
Thread-5 be ready to write data!
Thread-5 have write data: 7709
Thread-1 be ready to write data!
Thread-1 have write data: 7670
Thread-1 be ready to write data!
Thread-1 have write data: 7144
Thread-1 be ready to write data!
Thread-1 have write data: 5673
Thread-1 be ready to write data!
Thread-1 have write data: 7810
Thread-1 be ready to write data!
Thread-1 have write data: 3937
Thread-3 be ready to write data!
Thread-3 have write data: 4259
Thread-2 be ready to read data!
Thread-0 be ready to read data!
Thread-4 be ready to read data!
Thread-0 have read data :4259
Thread-2 have read data :4259
Thread-4 have read data :4259
Thread-5 be ready to write data!
Thread-5 have write data: 9939
Thread-5 be ready to write data! .....
转载:Java Lock机制解读的更多相关文章
- (转载)Java反射机制
Java反射机制是Java语言被视为准动态语言的关键性质.Java反射机制的核心就是允许在运行时通过Java Reflection APIs来取得已知名字的class类的相关信息,动态地生成此类,并调 ...
- [转载]Java 反射机制(包括组成、结构、示例说明等内容)
FROM:http://www.cnblogs.com/skywang12345/p/3345205.html 第1部分 Java 反射机制介绍 Java 反射机制.通俗来讲呢,就是在运行状态中,我们 ...
- Java回调机制解读
模块间调用 在一个应用系统中,无论使用何种语言开发,必然存在模块之间的调用,调用的方式分为几种: (1)同步调用 同步调用是最基本并且最简单的一种调用方式,类A的方法a()调用类B的方法b(),一直等 ...
- Java回调机制总结
调用和回调机制 在一个应用系统中, 无论使用何种语言开发, 必然存在模块之间的调用, 调用的方式分为几种: 1.同步调用 同步调用是最基本并且最简单的一种调用方式, 类A的方法a()调用类B的方法b( ...
- java异常处理机制 (转载)
java异常处理机制 本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 异常处理是程序设计中一个非常重要的方面,也是程序设计的一大难点,从C ...
- Java反射机制(转载)
原文链接:http://www.blogjava.net/zh-weir/archive/2011/03/26/347063.html Java反射机制是Java语言被视为准动态语言的关键性质.Jav ...
- 【转载】Java反射机制详解
转自:http://baike.xsoftlab.net/view/209.html#3_8 1反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对 ...
- Redisson 分布式锁实战与 watch dog 机制解读
Redisson 分布式锁实战与 watch dog 机制解读 目录 Redisson 分布式锁实战与 watch dog 机制解读 背景 普通的 Redis 分布式锁的缺陷 Redisson 提供的 ...
- Java I/O解读与使用实例
林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 摘要:本文主要讲解了Java I/O解读与使用实例. 一.I/O基本概念 I/O全称是Inpu ...
随机推荐
- Mysql update指定区间的数据
,) as a) Mysql 中 limit不能作为字句,所以要在limit外面再嵌套一层select
- 简述osi七层模型和TCP/IP五层模型
OSI七层模型 OSI七层模型的划分 应用层(Application).表示层(presentation).会话层(session).传输层(Transport).网络层(Network).数据链路层 ...
- redhat6.5 redis单节点多实例3A集群搭建
在进行搭建redis3M 集群之前,首先要明白如何在单节点上完成redis的搭建. 单节点单实例搭建可以参看这个网:https://www.cnblogs.com/butterflies/p/9628 ...
- 《DSP using MATLAB》Problem 7.25
代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...
- [C]奇数求和
/* 用递归算法实现,输入整数n(n>0), 求1+3+5+7….+(2*n-1) 的和 */ #include<stdio.h> int add(int n); int main( ...
- cordova闪屏插件插件使用:cordova-plugin-splashscreen
欢迎页本地插件,默认建议包含.启动本地应用时显示指定的图片(启动页) 1. 添加插件:cordova plugin add cordova-plugin-splashscreen 2. 调用方法:
- asp.net core webapi处理Post请求中的request payload
request payload的Content-Type实际上是text/plain的,如果请求的 Content-Type 为 application/json,这将导致415 Unsupporte ...
- 关于PCA
PCA是常见的降维技术. 对于使用PCA来进行降维的数据,需要进行预处理,是指能够实现均值为0,以及方差接近.如何来确定到底哪个维度是"主成分"?就要某个axis的方差. 为什么要 ...
- Flink
1. Flink表接受是基于dataset.datastream的:首先需要注册一个dataset,然后通过sql去查询这个dataset,返回的即使基于dataset查询结果,这个查询结构就是Fli ...
- Window服务项目脚手架
本人最近工作用到window服务程序,于是尝试分享下经验,开源了一个window服务脚手架项目,把window服务程序必不可少的组件集成进去,如日志组件log4net,window服务挂在后台,用日志 ...