Java ReadWriteLock
    开发中遇到并发的问题一般会用到锁,Synchronized存在明显的一个性能问题就是读与读之间互斥;
    ReadWriteLock是JDK5中提供的读写分离锁。读写分离锁可以有效地帮助减少锁竞争,以提升系统的性能。
    **ReadWriteLock**管理一组锁,一个是只读的锁,一个是写锁。
    Java并发库中ReetrantReadWriteLock实现了ReadWriteLock接口并添加了可重入的特性。
    读写锁**ReentrantReadWriteLock**:读读共享,读写互斥,写写互斥; 读写锁维护了一对锁,一个读锁,一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。在读多写少的情况下,读写锁能够提供比排他锁更好的并发性和吞吐量。
    image.png
    从源码中可以看出,读写锁中同样依赖队列同步器Sync(AQS)实现同步功能,而读写状态就是其同步器的同步状态。
    下面从例子中来说明:读读共享,读写互斥,写写互斥
    代码如下:

    1. public class ReentrantWriteReadLockTest {
    2. ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    3. ReadLock readLock = lock.readLock();
    4. WriteLock writeLock = lock.writeLock();
    5. public void read(){
    6. try {
    7. readLock.lock();
    8. System.out.println("线程"+Thread.currentThread().getName()+"进入。。。");
    9. Thread.sleep(3000);
    10. System.out.println("线程"+Thread.currentThread().getName()+"退出。。。");
    11. } catch (InterruptedException e) {
    12. e.printStackTrace();
    13. }finally{
    14. readLock.unlock();
    15. }
    16. }
    17. public void write(){
    18. try {
    19. writeLock.lock();
    20. System.out.println("线程"+Thread.currentThread().getName()+"进入。。。");
    21. Thread.sleep(3000);
    22. System.out.println("线程"+Thread.currentThread().getName()+"退出。。。");
    23. } catch (InterruptedException e) {
    24. e.printStackTrace();
    25. }finally{
    26. writeLock.unlock();
    27. }
    28. }
    29. public static void main(String[] args) {
    30. final ReentrantWriteReadLockTest wr = new ReentrantWriteReadLockTest();
    31. Thread t1 = new Thread(new Runnable() {
    32. public void run() {
    33. wr.read();
    34. }
    35. }, "t1");
    36. Thread t2 = new Thread(new Runnable() {
    37. public void run() {
    38. wr.read();
    39. }
    40. }, "t2");
    41. Thread t3 = new Thread(new Runnable() {
    42. public void run() {
    43. wr.write();
    44. }
    45. }, "t3");
    46. Thread t4 = new Thread(new Runnable() {
    47. public void run() {
    48. wr.write();
    49. }
    50. }, "t4");
    51. t1.start();
    52. t2.start();
    53. //t3.start();
    54. //t4.start();
    55. }
    56. }

    当启动线程t1和t2时,结果如下:
    image.png
    线程t1和t2可以同时进入,说明了读读共享!
    当启动线程t2和t3时,结果如下:
    image.png
    一个线程必须等待另一个线程退出,才能进入,说明了读写互斥!
    当启动线程t3和t4时,结果如下:
    image.png
    一个线程必须等待另一个线程退出,才能进入,说明了写写互斥!