**本文系作者原创,转载请注明:https://www.cnblogs.com/yanfei1819/p/10314533.html **

ReentrantLock

一、简介

ReentrantLock重入锁和synchronize关键字一样,是互斥锁。比synchronize关键字更加灵活。

二、基本方法

三、与synchronize对比

  1. 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();
    }
  2. 总结

    相同点:

    ​ 都是用于线程同步锁,都是互斥锁。

    不同点:

    ​ 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对比的更多相关文章

  1. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

  2. Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock

    在Java1.5中引入了两种显示锁,分别是可重入锁ReentrantLock和可重入读写锁ReentrantReadWriteLock.它们分别实现接口Lock和ReadWriteLock.(注意:s ...

  3. 从源码来看ReentrantLock和ReentrantReadWriteLock

    上一篇花了点时间将同步器看了一下,心中对锁的概念更加明确了一点,知道我们所使用到的锁是怎么样获取同步状态的,我们也写了一个自定义同步组件Mutex,讲到了它其实就是一个简版的ReentrantLock ...

  4. Lock、ReentrantLock、ReentrantReadWriteLock区别

    Lock Lock相比于synchronized具有更强大的功能,在jdk1.6之前,锁竞争激烈的情况下使用lock的实现类ReentrantLock甚至比synchronized具有更好的性能,1. ...

  5. 同步中的四种锁synchronized、ReentrantLock、ReentrantReadWriteLock、StampedLock

    为了更好的支持并发程序,JDK内部提供了多种锁.本文总结4种锁. 1.synchronized同步锁 使用: synchronized本质上就2种锁: 1.锁同步代码块 2.锁方法 可用object. ...

  6. Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...

  7. (四)Lock,ReentrantLock,ReentrantReadWriteLock类的使用以及相关api---synchronized进阶

    这篇博客记录了Lock,ReentrantLock,ReentrantReadWriteLock类的使用以及其一些api: 码字不易~~另外<java多线程编程核心技术>这本书读着很爽 前 ...

  8. Java并发编程总结3——AQS、ReentrantLock、ReentrantReadWriteLock(转)

    本文内容主要总结自<Java并发编程的艺术>第5章——Java中的锁. 一.AQS AbstractQueuedSynchronizer(简称AQS),队列同步器,是用来构建锁或者其他同步 ...

  9. Synchronize,Lock, ReentrantLock,ReentrantReadWriteLock

    下面ReentrantLock是Lock接口的具体实现 如果想在线程等待时(即等待获得锁时)可以被中断,用lockInterruptibly:注意:在线程已经获得锁正在执行时,用Synchronize ...

随机推荐

  1. 省队集训 Day3 吴清华

    [题目大意] 给网格图,共有$n * n$个关键节点,横向.纵向距离均为$d$,那么网格总长度和宽度均为$(n+1) * d + 1$,最外围一圈除了四角是终止节点.要求每个关键节点都要通过线连向终止 ...

  2. bzoj 1406 数论

    首先问题的意思就是在找出n以内的所有x^2%n=1的数,那么我们可以得到(x+1)(x-1)=y*n,那么我们知道n|(x+1)(x-1),我们设n=a*b,那么我们对于任意的a,我们满足n%a==0 ...

  3. fundamentals of the jQuery library

    1.why is jquery Only 32kB minified and gzipped. Can also be included as an AMD module Supports CSS3 ...

  4. Java 将html导出word格式

    @RequestMapping("download") public void exportWord( HttpServletRequest request, HttpServle ...

  5. Windows Resizer

    Windows ResizerWindows Resizer是chrome浏览器插件,可以调整视口大小

  6. sunos kernel src leakrs

    https://github.com/joede/libezV24 https://github.com/ysei/siriusSparcV8 https://github.com/omniti-la ...

  7. 如何使用vux创建vue项目

    1.安装vue-cli,通过vue-v可以查明 安装vue-cli步骤 vue init airyland/vux2 projectPath(项目名字) 2.安装依赖模块 方法1:npm instal ...

  8. 关于进度管理工具Gantt图

    关于进度管理工具Gantt图 18.以下关于进度管理工具图的叙述中,不正确的是( D). A.能清晰地表达每个任务的开始时间.结束时间和持续时间 B.能清晰地表达任务之间的并行关系 C.不能清晰地确定 ...

  9. 安装ubuntu-server16.0,设置WiFi

    想装个server版的Linux系统玩玩,下面记录一下遇到的坑. 1:安装语言选英文:可能是因为其他原因,我选中文的时候安装失败了,最后一次选中文的时候成功了. 2:以前装了一个ubuntu的,后面想 ...

  10. java字节码指令列表(转)

    字节码 助记符 指令含义 0x00 nop 什么都不做 0x01 aconst_null 将null推送至栈顶 0x02 iconst_m1 将int型-1推送至栈顶 0x03 iconst_0 将i ...