java并发编程中ReentrantLock可重入读写锁(java reentrantlock原理)

网友投稿 289 2022-07-30


目录一、ReentrantLock可重入锁二、ReentrantReadWriteLock读写锁三、读锁之间不互斥

一、ReentrantLock可重入锁

可重入锁ReentrantLock 是一个互斥锁,即同一时间只有一个线程能够获取锁定资源,执行锁定范围内的代码。这一点与synchronized 关键字十分相似。其基本用法代码如下:

Lock lock = new ReentrantLock(); //实例化锁

//lock.lock(); //上锁

booleancgsFyTaioL locked = lock.tryLock(); //尝试上锁

if(locked){

try {

//被锁定的同步代码块,同时只能被一个线程执行

}finally {

lock.unlock(); //放在finally代码块中,保证锁一定会被释放

}

}

通过lock函数获取锁,通过unlock函数释放锁。非常重要的是,需要把需要同步执行的代码放入 try/finally 代码块中,并在finally中将锁释放。ReentrantLock是可重入锁,即:(lock/unlok)动作里面可以嵌套(lock/unlock),针对同一个锁可以多次嵌套使用,不会产生死锁。但是lock函数与unlock函数在代码中必须成对出现,否则会出现死锁。

二、ReentrantReadWriteLock读写锁

ReentrantReadWriteLock类为读写锁实现类,针对某一个对象或可变变量,只要没有线程在修改它,这个对象或可变变量就可以同时被多个线程读取。ReentrantReadWriteLock将锁分为读锁和写锁,只要没有线程持有写锁的情况下,读锁可以由多个线程同时持有。

读锁-如果没有线程获取或请求写锁,那么多个线程可以获取读锁写锁-如果没有线程在读或写,那么只有一个线程可以获得写锁

简单的说就是ReentrantReadWriteLock可以保证最多同时有一个线程在写数据,或者可以同时有多个线程读数据。因此使用ReentrantReadWriteLock,在读操作比写操作更频繁的情况下,可以提高程序的性能和吞吐量。

下面我们用一个简单的例子,来解读一下如何应用读写锁。

public class TestReadWriteLock {

//可以同时执行3个线程任务的线程池

ExecutorService executor = Executors.newFixedThreadPool(3);

//读写目标,写线程放入数据到map,读线程从map读取数据

Map map = new HashMap<>();

//读写锁操作对象

ReadWriteLock lock = new ReentrantReadWriteLock();

//写操作函数

public void write(){

excgsFyTaioLecutor.submit(() -> { //线程池提交写操作任务

lock.writeLock().lock(); //加写锁

try {

http:// map.put("key", "val"); //写数据操作

Thread.sleep(2000);

} catch (InterruptedException e) {

e.printStackTrace();

} finally {

lock.writeLock().unlock(); //释放写锁

}

});

}

//读操作函数

public void read(){

lock.readLock().lock(); //加读锁

System.out.println(Thread.currentThread().getName() + "加读锁");

try {

System.out.println(map.get("key")); //读数据操作

} finally {

lock.readLock().unlock(); //释放读锁

System.out.println(Thread.currentThread().getName() + "释放读锁");

}

}

}

三、读锁之间不互斥

我们写一个测试方法,通过打印输出来理解读写锁控制代码的执行顺序。

//测试

public static void main(String[] args) {

TestReadWriteLock test = new TestReadWriteLock();

test.write(); //提交一次写操作任务,写一条数据

Runnable readTask = test::read; //线程方法read,实现线程Runnable接口的简便写法

test.executor.submit(readTask); //读1次(新读线程)

test.executor.submit(readTask); //读2次 (新读线程)

test.executor.shutdown();

}

执行上面的代码,可能会出现下面的输出

pool-1-thread-2加读锁pool-1-thread-3加读锁valvalpool-1-thread-3释放读锁pool-1-thread-2释放读锁

在pool-1-thread-2没有释放读锁情况下,pool-1-thread-3可以再次加读锁,并且都正确的读取到数据val。说明读锁之间是不互斥的。但是,在进行读操作(读锁生效)的时候,写操作是无法进行的(无法获取写锁),所以ReentrantReadWriteLock不支持同时加读锁和写锁。 这个结论我可以负责任告诉大家,这里我就不做验证了!


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot RedisTemplate分布式锁的项目实战(springboot原理)
下一篇:java并发高的情况下用ThreadLocalRandom来生成随机数(java threadlocalrandom)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~