共计 2381 个字符,预计需要花费 6 分钟才能阅读完成。
[TOC]
一、ReentrantLock 可重入锁
可重入锁ReentrantLock
是一个互斥锁,即同一时间只有一个线程可能获取锁定资源,执行锁定范畴内的代码。这一点与 synchronized 关键字十分相似。其根本用法代码如下:
Lock lock = new ReentrantLock(); // 实例化锁
//lock.lock(); // 上锁
boolean 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<String, String> map = new HashMap<>();
// 读写锁操作对象
ReadWriteLock lock = new ReentrantReadWriteLock();
// 写操作函数
public void write(){executor.submit(() -> { // 线程池提交写操作工作
lock.writeLock().lock(); // 加写锁
try {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 加读锁
val
val
pool-1-thread- 3 开释读锁
pool-1-thread- 2 开释读锁
在 pool-1-thread- 2 没有开释读锁状况下,pool-1-thread- 3 能够再次加读锁,并且都正确的读取到数据 val。阐明读锁之间是不互斥的 。然而, 在进行读操作 (读锁失效) 的时候,写操作是无奈进行的(无奈获取写锁),所以 ReentrantReadWriteLock 不反对同时加读锁和写锁。 这个论断我能够负责任通知大家,这里我就不做验证了!
欢送关注我的博客,更多精品常识合集
本文转载注明出处(必须带连贯,不能只转文字):字母哥博客 – zimug.com
感觉对您有帮忙的话,帮我点赞、分享!您的反对是我不竭的创作能源!。另外,笔者最近一段时间输入了如下的精品内容,期待您的关注。
- 《kafka 修炼之道》
- 《手摸手教你学 Spring Boot2.0》
- 《Spring Security-JWT-OAuth2 一本通》
- 《实战前后端拆散 RBAC 权限管理系统》
- 《实战 SpringCloud 微服务从青铜到王者》