ReentrantReadWriteLock读写锁的使用

  类ReentrantLock具有完全互斥排他的效果,即同一时间只有一个线程在执行ReentrantLock.lock()后面的代码。这样虽然保证了线程的安全性,但是效率低下。JDK提供了ReentrantReadWriteLock读写锁,使用它可以加快效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁ReemtrantReadWriteLock来提升该方法的运行速度。

  读写锁表示有两个锁,一个是读操作相关的锁,也称为共享锁;另一个是写操作相关的锁,也叫排他锁。也就是多个读锁之间不互斥,读锁与写锁互斥、写锁与写锁互斥。在没有线程Thread进行写入操作时,进行读取操作的多个Thread都可以获取读锁,而进行写入操作的Thread只有在获取写锁后才能进行写入操作。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。

1.读读共享

  读锁与读锁可以共享,这种锁一般用于只读操作,不对变量进行修改操作。

复制代码
package cn.qlq.thread.twelve;

import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.qlq.thread.one.RunnableThread;

public class Demo1 {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
    private static final Logger log = LoggerFactory.getLogger(Demo1.class);

    private int i;

    public String readI() {
        try {
            lock.readLock().lock();// 占用读锁
            log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {

        } finally {
            log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
            lock.readLock().unlock();// 释放读锁
        }
        return i + "";
    }

    public static void main(String[] args) {
        final Demo1 demo1 = new Demo1();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                demo1.readI();
            }
        };

        new Thread(runnable, "t1").start();
        new Thread(runnable, "t2").start();
        new Thread(runnable, "t3").start();

    }

}
复制代码

结果:

18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t2 占用读锁,i->0
18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t1 占用读锁,i->0
18:27:20 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t3 占用读锁,i->0
18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t3 释放读锁,i->0
18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t1 释放读锁,i->0
18:27:22 [cn.qlq.thread.twelve.Demo1]-[INFO] threadName -> t2 释放读锁,i->0

 

2.写写互斥

  写锁与写锁互斥,这就类似于ReentrantLock的作用效果。

复制代码
package cn.qlq.thread.twelve;

import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Demo2 {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
    private static final Logger log = LoggerFactory.getLogger(Demo2.class);

    private int i;

    public void addI() {
        try {
            lock.writeLock().lock();// 占用写锁
            log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
            Thread.sleep(2 * 1000);
            i++;
        } catch (InterruptedException e) {

        } finally {
            log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
            lock.writeLock().unlock();// 释放写锁
        }
    }

    public static void main(String[] args) {
        final Demo2 demo1 = new Demo2();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                demo1.addI();
            }
        };

        new Thread(runnable, "t1").start();
        new Thread(runnable, "t2").start();
        new Thread(runnable, "t3").start();

    }

}
复制代码

结果:(从时间可以看出实现了互斥效果)

18:31:31 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t1 占用写锁,i->0
18:31:33 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t1 释放写锁,i->1
18:31:33 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t2 占用写锁,i->1
18:31:35 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t2 释放写锁,i->2
18:31:35 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t3 占用写锁,i->2
18:31:37 [cn.qlq.thread.twelve.Demo2]-[INFO] threadName -> t3 释放写锁,i->3

 

3.读写互斥

复制代码
package cn.qlq.thread.twelve;

import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 读写互斥
 * 
 * @author Administrator
 *
 */
public class Demo3 {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
    private static final Logger log = LoggerFactory.getLogger(Demo3.class);

    private int i;

    public String readI() {
        try {
            lock.readLock().lock();// 占用读锁
            log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {

        } finally {
            log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
            lock.readLock().unlock();// 释放读锁
        }
        return i + "";
    }

    public void addI() {
        try {
            lock.writeLock().lock();// 占用写锁
            log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
            Thread.sleep(2 * 1000);
            i++;
        } catch (InterruptedException e) {

        } finally {
            log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
            lock.writeLock().unlock();// 释放写锁
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final Demo3 demo1 = new Demo3();

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo1.readI();
            }
        }, "t1").start();

        Thread.sleep(1 * 1000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo1.addI();
            }
        }, "t2").start();

    }

}
复制代码

结果:

18:34:59 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 占用读锁,i->0
18:35:01 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 释放读锁,i->0
18:35:01 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 占用写锁,i->0
18:35:03 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 释放写锁,i->1

 

4.写读互斥

  写锁与读锁也是互斥的。先占用写锁后读锁进行抢占也会等待写锁释放。

复制代码
package cn.qlq.thread.twelve;

import java.util.concurrent.locks.ReentrantReadWriteLock;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 读写互斥
 * 
 * @author Administrator
 *
 */
public class Demo3 {
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();// 读写锁
    private static final Logger log = LoggerFactory.getLogger(Demo3.class);

    private int i;

    public String readI() {
        try {
            lock.readLock().lock();// 占用读锁
            log.info("threadName -> {} 占用读锁,i->{}", Thread.currentThread().getName(), i);
            Thread.sleep(2 * 1000);
        } catch (InterruptedException e) {

        } finally {
            log.info("threadName -> {} 释放读锁,i->{}", Thread.currentThread().getName(), i);
            lock.readLock().unlock();// 释放读锁
        }
        return i + "";
    }

    public void addI() {
        try {
            lock.writeLock().lock();// 占用写锁
            log.info("threadName -> {} 占用写锁,i->{}", Thread.currentThread().getName(), i);
            Thread.sleep(2 * 1000);
            i++;
        } catch (InterruptedException e) {

        } finally {
            log.info("threadName -> {} 释放写锁,i->{}", Thread.currentThread().getName(), i);
            lock.writeLock().unlock();// 释放写锁
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final Demo3 demo1 = new Demo3();

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo1.addI();
            }
        }, "t2").start();

        Thread.sleep(1 * 1000);

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo1.readI();
            }
        }, "t1").start();
    }

}
复制代码

结果:

18:36:14 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 占用写锁,i->0
18:36:16 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t2 释放写锁,i->1
18:36:16 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 占用读锁,i->1
18:36:18 [cn.qlq.thread.twelve.Demo3]-[INFO] threadName -> t1 释放读锁,i->1

 

总结: 读写、写读、写写都是互斥的,而读读是异步非互斥的。

      也就是只要有写锁的参与就会进行同步,所以写锁也被称为排他锁,读锁被称为共享锁。

 

posted @   QiaoZhi  阅读(1992)  评论(0编辑  收藏  举报
编辑推荐:
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
历史上的今天:
2017-12-21 【IntelliJ】IntelliJ IDEA常用设置及快捷键以及自定义Live templates
2017-12-21 【Intellij】Intellij Idea 2017创建web项目及tomcat部署实战
2017-12-21 【IntelliJ 】IntelliJ IDEA 15 创建maven项目
2017-12-21 【IntelliJ】IntelliJ IDEA的安装破解及使用
2017-12-21 maven坐标查询
点击右上角即可分享
微信分享提示