Lock 比传统线程模型中的 synchronized 方式更加面向对象, 与生活中的锁类似, 锁本身也应该是一个对象. 两个线程执行的代码片段要实现同步互斥的效果, 它们必须用同一个 Lock 对象.
读写锁: 分为读锁和写锁, 多个读锁不互斥, 读锁与写锁互斥, 这是由 jvm 自己控制的, 你只要上好相应的锁即可. 如果你的代码只读数据, 可以很多人同时读, 但不能同时写, 那就上读锁; 如果你的代码修改数据, 只能有一个人在写, 且不能同时读取, 那就上写锁. 总之, 读的时候上读锁, 写的时候上写锁!
ReentrantReadWriteLock 会使用两把锁来解决问题, 一个读锁, 一个写锁
线程进入读锁的前提条件:
没有其他线程的写锁,
没有写请求或者有写请求, 但调用线程和持有锁的线程是同一个
线程进入写锁的前提条件:
没有其他线程的读锁
没有其他线程的写锁
到 ReentrantReadWriteLock, 首先要做的是与 ReentrantLock 划清界限. 它和后者都是单独的实现, 彼此之间没有继承或实现的关系. 然后就是总结这个锁机制的特性了:
(a). 重入方面其内部的 WriteLock 可以获取 ReadLock, 但是反过来 ReadLock 想要获得 WriteLock 则永远都不要想.
(b).WriteLock 可以降级为 ReadLock, 顺序是: 先获得 WriteLock 再获得 ReadLock, 然后释放 WriteLock, 这时候线程将保持 Readlock 的持有. 反过来 ReadLock 想要升级为 WriteLock 则不可能, 为什么? 参看 (a), 呵呵.
(c).ReadLock 可以被多个线程持有并且在作用时排斥任何的 WriteLock, 而 WriteLock 则是完全的互斥. 这一特性最为重要, 因为对于高读取频率而相对较低写入的数据结构, 使用此类锁同步机制则可以提高并发量.
(d). 不管是 ReadLock 还是 WriteLock 都支持 Interrupt, 语义与 ReentrantLock 一致.
(e).WriteLock 支持 Condition 并且与 ReentrantLock 语义一致, 而 ReadLock 则不能使用 Condition, 否则抛出 UnsupportedOperationException 异常.
实例代码
- public class UseReentrantReadWriteLock {
- private ReentrantReadWriteLock rwLock =
- new ReentrantReadWriteLock();
- private ReentrantReadWriteLock.ReadLock readLock = rwLock.readLock();
- private ReentrantReadWriteLock.WriteLock writeLock = rwLock.writeLock();
- public void read(){
- try {
- readLock.lock();
- System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
- Thread.sleep(3000);
- System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally {
- readLock.unlock();
- }
- }
- public void write(){
- try {
- writeLock.lock();
- System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
- Thread.sleep(3000);
- System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }finally {
- writeLock.unlock();
- }
- }
- public static void main(String[] args){
- final UseReentrantReadWriteLock urrw =
- new UseReentrantReadWriteLock();
- Thread t1 =
- new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.read();
- }
- },"t1");
- Thread t2 = new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.read();
- }
- },"t2");
- Thread t3 = new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.write();
- }
- },"t3");
- Thread t4 = new Thread(new Runnable() {
- @Override
- public void run() {
- urrw.write();
- }
- }, "t4");
- t1.start();
- //t3.start();
- //t4.start();
- t2.start();
- }
- }
t3 和 t4 两个线程不能同时运行, t1 和 t2 可以同时运行
- /**
- 缓存器
- */
- public class CacheDemo {
- // 缓存器
- private Map<String,Object> map =
- new HashMap<>();
- private ReadWriteLock rwl = new ReentrantReadWriteLock();
- public Object get(String id) {
- Object value = null;
- rwl.readLock().lock();// 首先开启读锁, 从缓存中去取
- try {
- value = map.get(id);
- if (value == null) {// 如果缓存中没有释放读锁, 上写锁
- rwl.readLock().unlock();
- rwl.writeLock().lock();
- try {
- if (value == null) {
- value = "aaa";// 此时可以去数据库中查找, 这里简单的模拟一下
- }
- } finally {
- rwl.writeLock().unlock();// 释放写锁
- }
- rwl.writeLock().unlock();// 然后再上读锁
- }
- } finally {
- rwl.readLock().unlock();
- }
- return value;
- }
- }
来源: http://www.jianshu.com/p/b52671244449