ReentrantLock和ReentrantReadWriteLock对比
**本文系作者原创,转载请注明:https://www.cnblogs.com/yanfei1819/p/10314533.html **
ReentrantLock
一、简介
ReentrantLock重入锁和synchronize关键字一样,是互斥锁。比synchronize关键字更加灵活。
二、基本方法
三、与synchronize对比
demo演示
线程不安全:
public class WriteAndReadThread {
public static void main(String[] args) {
Person person = new Person();
Thread t1 = new Output(person);
Thread t2 = new Input(person);
t1.start();
t2.start();
}
}
// 写数据的线程
class Output extends Thread {
private Person person;
public Output(Person person) {
this.person = person;
}
@Override
public void run() {
int count = 0;
while (true) {
if (count == 0) {
person.name = "小明";
person.gender = "男";
} else {
person.name = "小红";
person.gender = "女";
}
count = (count + 1) % 2; // 奇数偶数轮流展现
person.flag = true;
}
}
}
// 读数据的线程
class Input extends Thread {
private Person person;
public Input(Person person) {
this.person = person;
}
@Override
public void run() {
while (true) {
System.out.println(person.name + "," + person.gender);
}
}
}
class Person {
public String name;
public String gender;
public boolean flag = false;
}
以上代码没有考虑线程安全问题,读写线程会竞争共享资源,导致数据紊乱。
1)线程安全(加synchronize关键字):
public class ThreadTwo {
public static void main(String[] args) {
Person person = new Person();
Thread t1 = new Output(person);
Thread t2 = new Input(person);
t1.start();
t2.start();
}
} // 写的线程
class Output extends Thread{
private Person person;
public Output(Person person){
this.person=person;
}
@Override
public void run(){
int count = 0;
while (true){
synchronized (person){
if(person.flag){
try {
person.wait(); // 唤醒等待的线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(count==0){
person.name="小明";
person.gender="男";
}else {
person.name="小红";
person.gender="女";
}
count=(count+1)%2;
person.flag=true;
person.notify();
}
}
}
}
// 读数据的线程
class Input extends Thread{
private Person person;
public Input(Person person){
this.person=person;
}
@Override
public void run(){
while (true){
synchronized (person){
if(!person.flag){
try {
person.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(person.name+","+person.gender);
person.flag=false;
person.notify();
}
}
}
}
class Person{
public String name;
public String gender;
public boolean flag=false;
}
2)线程安全(用Lock):
public class LockDemo {
public static void main(String[] args) {
Person2 person2 = new Person2();
Condition condition = person2.lock.newCondition();
Input2 input2 = new Input2(person2,condition);
Output2 output2 = new Output2(person2,condition);
input2.start();
output2.start();
}
} // 写的线程
class Output2 extends Thread {
private Person2 person;
private Condition condition;
public Output2(Person2 person, Condition condition) {
this.person = person;
this.condition = condition;
}
@Override
public void run() {
int count = 0;
while (true) {
try {
person.lock.lock();
if (person.flag) {
try {
condition.await(); // 使线程休眠,作用等于synchronize中的thread.wait()方法
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (count == 0) {
person.name = "小明";
person.gender = "男";
} else {
person.name = "小红";
person.gender = "女";
}
count = (count + 1) % 2;
person.flag = true;
condition.signal();
}catch (Exception e){
}finally {
person.lock.unlock(); // 必须手动关闭线程
}
}
}
} // 读的线程
class Input2 extends Thread {
private Person2 person;
private Condition condition; // 该接口的作用是精确控制锁的行为
public Input2(Person2 person, Condition condition) {
this.person = person;
this.condition = condition;
} @Override
public void run() {
while (true) {
try {
person.lock.lock();
if (!person.flag) {
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(person.name + "," + person.gender);
person.flag = false;
condition.signal();//唤醒线程
}catch (Exception e){ }finally {
person.lock.unlock();
}
}
}
} class Person2 {
public String name;
public String gender;
public boolean flag = false; // 该属性是用来控制线程之间的通讯
Lock lock = new ReentrantLock();
}
总结
相同点:
都是用于线程同步锁,都是互斥锁。
不同点:
1.如果用汽车来类比,synchronize相当于自动挡,Lock相当于手动挡。即:synchronize是内置锁,只要加上synchronize的代码的地方开始,代码结束的地方自动释放资源。lock必须手动加锁,手动释放资源。
2.synchronize优点是代码量少,自动化。缺点是扩展性低,不够灵活。
3.Lock优点是扩展性好,灵活。缺点是代码量相对稍多。
4.释放锁的情况:
synchronize:1)线程执行完毕;2)线程发生异常;3)线程进入休眠状态。
Lock:通过unLock()方法。
注意点:
1.wait()和notify()/notifyAll()必须出现在synchronize修饰的代码块中;
2.资源的释放通常放在finally中;
3.最好不要将lock()方法写在try{}中,因为如果 发生异常的话,抛出异常,同时锁资源无法释放。
ReentrantReadWriteLock
一、简介
ReentrantLock虽然可以灵活地实现线程安全,但是他是一种完全互斥锁,即某一时刻永远只允许一个线程访问共享资源,不管是读数据的线程还是写数据的线程。这导致的结果就是,效率低下。
ReentrantReadWriteLock类的出现很好的解决了该问题。该类实现了ReadWriteLock接口,而ReadWriteLock接口中维护了两个锁:读锁(共享锁)和写锁(排他锁)。
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
二、基本方法
三、使用
ReentrantReadWriteLock中维护了读锁和写锁。允许线程同时读取共享资源;但是如果有一个线程是写数据,那么其他线程就不能去读写该资源。即会出现三种情况:读读共享,写写互斥,读写互斥。
以下以代码演示:
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
Lock readLock = reentrantReadWriteLock.readLock();
Lock writeLock = reentrantReadWriteLock.readLock();
new Thread(new Runnable() {
@Override
public void run() {
// writeLock.lock(); // 写锁加锁
readLock.lock(); // 读锁加锁
try {
for (int i = 0; i < 10; i++) {
System.out.println("我是第一个线程,线程名是"+Thread.currentThread().getName()+",当前时间是"+System.currentTimeMillis());
}
Thread.sleep(2000); // 休眠2s
}catch (Exception e){
}finally {
// writeLock.unlock();// 写锁释放锁
readLock.unlock();// 读锁释放锁
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
// writeLock.lock(); // 写锁加锁
readLock.lock();// 读锁加锁
try {
for (int i = 0; i < 10; i++) {
System.out.println("我是第二个线程,线程名是"+Thread.currentThread().getName()+",当前时间是"+System.currentTimeMillis());
}
}catch (Exception e){
}finally {
// writeLock.unlock();// 写锁释放锁
readLock.unlock();
}
}
}).start();
以上两个线程如果是读锁,则会同时执行(打印的时间几乎相等),但是如果是写锁,则不会同时执行(打印时间相差2s)。
ReentrantLock和ReentrantReadWriteLock对比的更多相关文章
- java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock
原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...
- Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock
在Java1.5中引入了两种显示锁,分别是可重入锁ReentrantLock和可重入读写锁ReentrantReadWriteLock.它们分别实现接口Lock和ReadWriteLock.(注意:s ...
- 从源码来看ReentrantLock和ReentrantReadWriteLock
上一篇花了点时间将同步器看了一下,心中对锁的概念更加明确了一点,知道我们所使用到的锁是怎么样获取同步状态的,我们也写了一个自定义同步组件Mutex,讲到了它其实就是一个简版的ReentrantLock ...
- Lock、ReentrantLock、ReentrantReadWriteLock区别
Lock Lock相比于synchronized具有更强大的功能,在jdk1.6之前,锁竞争激烈的情况下使用lock的实现类ReentrantLock甚至比synchronized具有更好的性能,1. ...
- 同步中的四种锁synchronized、ReentrantLock、ReentrantReadWriteLock、StampedLock
为了更好的支持并发程序,JDK内部提供了多种锁.本文总结4种锁. 1.synchronized同步锁 使用: synchronized本质上就2种锁: 1.锁同步代码块 2.锁方法 可用object. ...
- Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)
关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...
- (四)Lock,ReentrantLock,ReentrantReadWriteLock类的使用以及相关api---synchronized进阶
这篇博客记录了Lock,ReentrantLock,ReentrantReadWriteLock类的使用以及其一些api: 码字不易~~另外<java多线程编程核心技术>这本书读着很爽 前 ...
- Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock(转)
本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步 ...
- Synchronize,Lock, ReentrantLock,ReentrantReadWriteLock
下面ReentrantLock是Lock接口的具体实现 如果想在线程等待时(即等待获得锁时)可以被中断,用lockInterruptibly:注意:在线程已经获得锁正在执行时,用Synchronize ...
随机推荐
- UVA 11105 Semi-prime H-numbers
https://vjudge.net/problem/UVA-11105 筛法 #include<cstdio> #include<cstring> #define N 100 ...
- Packet Tracer 5.0 构建CCNA实验(2)—— 配置VLAN
Packet Tracer 5.0 构建CCNA实验(2)—— 配置VLAN Vlan(Virtual Local Area Network) 即虚拟局域网.VLAN可以把同一个物理网络划分为多个逻辑 ...
- 「6月雅礼集训 2017 Day4」暴力大神hxx
[题目大意] 给出一个n重循环,每重循环有范围$[l, r]$,其中$l$,$r$可能是之前的变量,也可能是常数.求循环最底层被执行了多少次. 其中,保证每个循环的$l$,$r$最多有一个是之前的变量 ...
- 【BZOJ】1455 罗马游戏
[算法]可并堆(左偏树) #include<cstdio> #include<algorithm> using namespace std; ; int l[maxn],r[m ...
- 对vue中 默认的 config/index.js:配置的详细理解 -【以及webpack配置的理解】-config配置的目的都是为了服务webpack的配置,给不同的编译条件提供配置
当我们需要和后台分离部署的时候,必须配置config/index.js: 用vue-cli 自动构建的目录里面 (环境变量及其基本变量的配置) var path = require('path') ...
- js中的true和false
1.false undefined.NaN.0.null和空字符串''均被视为false 2.true 除上述以外的其它情况一律被视作true
- hydra 密码破解工具详解
一.简介 hydra是著名黑客组织thc的一款开源的暴力密码破解工具,可以在线破解多种密码.官 网:http://www.thc.org/thc-hydra,可支持AFP, Cisco AAA, Ci ...
- vue-实现倒计时功能
JavaScript 创建一个 countdown 方法,用于计算并在控制台打印距目标时间的日.时.分.秒数,每隔一秒递归执行一次. msec 是当前时间距目标时间的毫秒数,由时间戳相减得到,我们将以 ...
- tornado简单使用
这篇适用于快速上手想了解更深:http://www.tornadoweb.cn/ https://tornado-zh.readthedocs.io/zh/latest/ Tornado 是 Fr ...
- Optimizing subroutine calls based on architecture level of called subroutine
A technique is provided for generating stubs. A processing circuit receives a call to a called funct ...