Java多线程之读写锁ReentrantReadWriteLock类使用

本文介绍了Java中的ReentrantReadWriteLock读写锁,对比了它与ReentrantLock的区别,强调了读写锁在提高并发性能上的优势。读写锁允许多个线程同时读取,但在写操作时实现互斥,确保数据一致性。文中通过实例展示了读读共享、写写互斥、读写互斥和写读互斥四种情况,证明了读写锁在处理读多写少场景时的有效性。
摘要由CSDN通过智能技术生成

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

读写锁简介

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


下面我们来看ReentrantReadWriteLock类的使用实例:

一、读读共享

创建一个读写服务类ReadWriteService.java,代码如下:

public class ReadWriteService {
	// 创建读写锁
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
	// 读方法
    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("获取读锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.readLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

创建两个线程,调用读写服务。代码如下:

线程一

public class Thread1 extends Thread {
    private ReadWriteService readWriteService;

    public Thread1(ReadWriteService readWriteService){
        super();
        this.readWriteService = readWriteService;
    }

    @Override
    public void run() {
        readWriteService.read();
    }
}

线程二

public class Thread2 extends Thread{
    private ReadWriteService readWriteService;

    public Thread2(ReadWriteService readWriteService){
        super();
        this.readWriteService = readWriteService;
    }

    @Override
    public void run() {
        readWriteService.read();
    }
}

启动线程,代码如下:

public class Main {
        public static void main(String[] args) {
            ReadWriteService service = new ReadWriteService();
            Thread1 a = new Thread1(service);
            a.setName("A");
            Thread2 b = new Thread2(service);
            b.setName("B");
            a.start();
            b.start();
        }
}

输出如下:
在这里插入图片描述
从控制台中打印的时间来看,两个线程几乎同时进入lock()方法后面的代码。说明在此使用了lock.readLock()读锁的确可以提高程序运行效率,他允许多个线程同时执行lock()方法后面的代码。

二、写写互斥

改一下读写服务类ReadWriteService.java,代码如下:

public class ReadWriteService {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取写锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

然后修改一下两个线程中调用ReadWriteService的方法,启动

在这里插入图片描述
从运行结果可以看到使用写锁代码lock.writeLock()的效果就是同一时间只允许一个线程执行lock()方法后面的代码。

三、读写互斥

修改ReadWriteService.java代码

public class ReadWriteService {
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    public void read() {
        try {
            try {
                lock.readLock().lock();
                System.out.println("获取读锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.readLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public void write() {
        try {
            try {
                lock.writeLock().lock();
                System.out.println("获取写锁" + Thread.currentThread().getName()
                        + "==" + System.currentTimeMillis());
                Thread.sleep(5000);
            } finally {
                lock.writeLock().unlock();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

两个线程类中线程一调用读方法,线程二调用写方法;
然后修改启动类:

public class Main {
        public static void main(String[] args) {
            ReadWriteService service = new ReadWriteService();
            Thread1 a = new Thread1(service);
            a.setName("A");
            a.start();
            Thread2 b = new Thread2(service);
            b.setName("B");
            b.start();
        }
 }

输出:

在这里插入图片描述
由此可以说明“读写”操作也是互斥的,而且下一个示例说明了“写读”操作也是互斥的。也就是说,只要出现“写操作”的过程,就会是互斥的。

四、写读互斥

ReadWriteService.java代码还是跟读写互的一样,只要修改启动类线程执行顺序;代码如下:

public class Main {
        public static void main(String[] args) {
            ReadWriteService service = new ReadWriteService();
            Thread2 b = new Thread2(service);
            b.setName("B");
            b.start();
            Thread1 a = new Thread1(service);
            a.setName("A");
            a.start();
        }
}

运行结果:

在这里插入图片描述
可以看到“写读”操作也是互斥的。

总结:
ReentrantReadWriteLock类是读写锁,他对于“读写”、“写读”和“写写”都是互斥的;而“读读”是异步的,非互斥的。也就是只要包含写操作,就是互斥的;但是对于读读就是共享的。即多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UnIQUE Eason

最喜欢你一言不合就打赏的样子了

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值