今天讲另一个并发工具,叫读写锁。读写锁是一种分离锁,是锁应用中的一种优化手段。
考虑读多写少的情况,这时如果我们用synchronized或ReentrantLock直接修饰读/写方法未尝不可,如:
1 public static class Rw { 2 private int val; 3 4 public synchronized int read() throws InterruptedException { 5 Thread.sleep(1000); 6 return val; 7 } 8 9 public synchronized void write(int value) throws InterruptedException { 10 Thread.sleep(1000); 11 this.val = value; 12 } 13 }
简单有效。
如果我们想做点优化的话(前面说了读的情况比较多),也许要用到读写锁ReadWriteLock了`。
先看代码:
1 public static class Rw { 2 private int val; 3 4 public int read(Lock lock) throws InterruptedException { 5 try { 6 lock.lock(); 7 Thread.sleep(1000); 8 return val; 9 } finally { 10 lock.unlock(); 11 } 12 } 13 14 public void write(Lock lock, int value) throws InterruptedException { 15 try { 16 lock.lock(); 17 Thread.sleep(1000); 18 this.val = value; 19 } finally { 20 lock.unlock(); 21 } 22 } 23 }
调用:
1 private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); 2 3 public static void main(String[] args) { 4 final Rw rw = new Rw(); 5 6 for (int i = 18; i < 20; i++) { 7 new Thread(() -> { 8 try { 9 rw.write(readWriteLock.writeLock(),1); 10 } catch (InterruptedException e) { 11 e.printStackTrace(); 12 } 13 }).start(); 14 } 15 for (int i = 0; i < 18; i++) { 16 new Thread(() -> { 17 try { 18 int read = rw.read(readWriteLock.readLock()); 19 System.out.println(read); 20 } catch (InterruptedException e) { 21 e.printStackTrace(); 22 } 23 }).start(); 24 } 25 }
ReentrantReadWriteLock是ReadWriteLock的常用子类。
代码逻辑比较简单,读的时候上读锁,写的时候上写锁。只有写的时候会阻塞等待,所以代码大概2秒钟执行结束。
这里面只需要注意一个问题:所有和写相关的都会阻塞,比如读-写同时进行,也会阻塞。