IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java多线程-10 (Lock锁之ReentrantReadWriteLock 读写锁) -> 正文阅读

[Java知识库]Java多线程-10 (Lock锁之ReentrantReadWriteLock 读写锁)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?ReentrantReadWriteLock

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 个人博客:www.xiaobeigua.icu?


1.3 ReentrantReadWriteLock 读写锁

1.3.1认识读写锁

????????synchronized 内部锁与 ReentrantLock 锁都是独占锁(排它锁), 同一 时间只允许一个线程执行同步代码块,可以保证线程的安全性,但是执行效率低。

?????????ReentrantReadWriteLock 读写锁?是一种改进的排他锁,也可以称作 共享/排他锁。允许多个线程同时读取共享数据,但是一次只允许一个线程对共享数据进行更新。

?????????读写锁通过读锁与写锁来完成读写操作,线程在读取共享数据前必须先持有读锁,该读锁可以同时被多个线程持有,即它是共享的。

????????线程在修改共享数据前必须先持有写锁,写锁是排他的,一个线程持有写锁时其他线程无法获得相应的锁,读锁只是在读线程之间共享,任何一个线程持有读锁时,其他线程都无法获得写锁, 保证线程在读取数据期间没有其他线程对数据进行更新,使得读线程能够读到数据的最新值,保证在读数据期间共享变量不被修改,这也保证了数据共享之间的可见性。

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????????

锁类型获得条件排他性作用
读锁写锁未被任意线程持有对读线程是共享的,对写线程是排他的允许多个读线程可以同时读 取共享数据,保证在读共享数 据时,没有其他线程对共享数 据进行修改
写锁该写锁未被其他线程持 有,并且相应的读锁也未被其他线程持有对读线程或者写线程都是排他的保证写线程以独占的方式修 改共享数据

????????读写锁允许 读读共享读写互斥,写写互斥

????????在java.util.concurrent.locks包中定义了ReadWriteLock接口,该接口中定义了 readLock()返回读锁,定义 writeLock()方法返回写锁。该接口的实现类是 ReentrantReadWriteLock。

????????注意 readLock()与 writeLock()方法返回的锁对象是同一个锁的两个不同的角色,就像作者本人人在学校里是学生,下对象面前就是威猛先生(手动狗头),不是分别获得两个不同的锁。

????????锁?ReadWriteLock 接口实例可以充当两个角色。

????????读写锁的其他使用方法:? ? ? ? ? ? ??

//定义读写锁
ReadWriteLock rwLock = new ReentrantReadWriteLock();

//获得读锁 
Lock readLock = rwLock.readLock();

//获得写锁 
Lock writeLock = rwLock.writeLock();



//读数据
try{
    readLock.lock(); //申请读锁
    读取共享数据
}finally{
    readLock.unlock(); //总是在 finally 子句中释放锁
}

//写数据
try{
    writeLock.lock(); //申请写锁
    更新修改共享数据
}finally{
    writeLock.unlock(); //总是在 finally 子句中释放锁
}

1.3.2? 读读共享

????????ReadWriteLock 读写锁可以实现多个线程同时读取共享数据,即读 读共享,可以提高程序的读取数据的效率。

例子:创建5个线程来获取读锁,线程获取之后,未释放锁,看看其它线程获取情况

public class TestOne {

    //创建读写锁
    static  ReadWriteLock readWriteLock=  new ReentrantReadWriteLock();
    //创建读锁
    static  Lock readLock = readWriteLock.readLock();

    public static void main(String[] args) {
        TestOne t1=new TestOne();
        //创建5个线程使用锁
        for (int i=0;i<5;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    t1.read();
                }
            }).start();
        }

    }

    //创建方法 供线程调用
    public void read(){
        
        try {
            //申请读锁
            readLock.lock();
            System.out.println(Thread.currentThread().getName()+"获得读锁");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程获得锁未释放锁
        }


    }
}

结果:

?结论:在一个线程获取锁未释放的条件下,其他线程还可以继续获取锁,表明了,读锁在读线程之间是共享的,提高了数据的读取效率。

1.3.3?写写互斥

?????????通过 ReadWriteLock 读写锁中的写锁,只允许有一个线程执行 lock() 后面的代码。

例子:创建两个线程来争夺写锁,看看一个线程获得锁后,不释放? 看另一个锁的情况

public class TestOne {
    //创建读写锁
   static ReadWriteLock readWriteLock=  new ReentrantReadWriteLock();
    //创建写锁
   static Lock writeLock =readWriteLock.writeLock();

    public static void main(String[] args) {


        TestOne t1=new TestOne();
        //创建2个线程使用锁
        for (int i=0;i<2;i++){
            new Thread(new Runnable() {
                @Override
                public void run() {
                    t1.write();
                }
            }).start();
        }

    }

    //创建方法 供线程调用
    public void write(){
        try {
            //申请写锁
            System.out.println(Thread.currentThread().getName()+"尝试获取写锁...");
            writeLock.lock();
            System.out.println(Thread.currentThread().getName()+"获得写锁成功,开始修改数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //线程获得写锁 不释放
        }


    }
}

结果:

????????

?结论:在一个线程获得写锁后,只要不释放锁,别的线程就要一直等待,这说明了写锁是互斥的,这也保证了数据共享的原子性

1.3.4?读写互斥

????????写锁是独占锁,是排他锁,所以读线程与写线程也是互斥的,有写锁被线程占有,那么别的锁就不可能被别的线程占有

例子:创建3 个线程 一个线程先获取写锁,两个线程尝试获取读锁 看情况

public class TestOne {
    //创建读写锁
    static ReadWriteLock readWriteLock=  new ReentrantReadWriteLock();
    //创建读锁
    static Lock readLock=readWriteLock.readLock();
    //创建写锁
    static Lock writeLock =readWriteLock.writeLock();

    public static void main(String[] args) throws InterruptedException {

        TestOne t1=new TestOne();
        //创建1个线程使用写锁,不释放
        new Thread(new Runnable() {
            @Override
            public void run() {
                t1.write();
            }
        }).start();
        //main线程休眠1s确保 线程获得写锁
        Thread.sleep(1000);

        //创建2个线程尝试获得读锁
        new Thread(new Runnable() {
            @Override
            public void run() {
                t1.read();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                t1.read();
            }
        }).start();


    }

    //创建写锁方法 供线程调用
    public void write(){
        try {
            //申读读锁
            System.out.println(Thread.currentThread().getName()+"尝试获取写锁...");
            writeLock.lock();
            System.out.println(Thread.currentThread().getName()+"获得写锁成功,开始修改数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //writeLock.unlock();
            //线程获得读锁 不释放
        }
    }

    //创建都锁方法
    public void read(){
        try {
            //申请都锁
            System.out.println(Thread.currentThread().getName()+"尝试获取读锁...");
            readLock.lock();
            System.out.println(Thread.currentThread().getName()+"获得读锁成功,开始读取数据");
            } catch (Exception e) {
                e.printStackTrace();
        } finally {

             //线程获得写锁 不释放
        }
    }


}

?结果:线程0获取写锁后未释放,其他线程都处于等待状态,无法获取读锁

????????

如果获取写锁了之后 再释放了它,看其他线程的情况:

?结果:写锁被释放后,其他两个线程可以获取读锁

?结论:

????????可以看出在一个线程获取到写锁后,未释放写锁之前,其他线程也是无法获取读锁的,因为写锁是排他锁,就和synchronized () 和可重入锁一样的效果。也是未来共享数据的原子性。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-08-10 13:17:12  更:2021-08-10 13:18:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 5:50:59-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码