乐趣区

关于java:读写锁的原理

读写锁的应用

读写锁在 Java 中是 ReentrantReadWriteLock,应用形式是:

import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriteLockDemo implements TestDemo {ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    ReentrantReadWriteLock.ReadLock readLock = lock.readLock();
    ReentrantReadWriteLock.WriteLock writeLock = lock.writeLock();

    private int x = 0;

    private void count() {writeLock.lock();
        try {x++;} finally {writeLock.unlock();// 保障当读的时候如果出现异常,会开释锁,synchronized 为什么不必呢?因为 synchronized 外部曾经帮咱们做了~
        }
    }

    private void print(int time) {readLock.lock();
        try {for (int i = 0; i < time; i++) {System.out.print(x + " ");
            }
            System.out.println();} finally {readLock.unlock();// 保障当读的时候如果出现异常,会开释锁,synchronized 为什么不必呢?因为 synchronized 外部曾经帮咱们做了~
        }
    }

    @Override
    public void runTest() {}
}

ReentrantReadWriteLock 和 ReentrantLock 的区别?

应用 ReentrantReadWriteLock 读写锁的形式,会调用 readLock() 和 writeLock() 两个办法,看下他们的源码:

public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock;}
public ReentrantReadWriteLock.ReadLock  readLock()  { return readerLock;}

复制代码能够看到用到了 WriteLock 和 ReadLock 两个动态外部类,他们对锁的实现如下:

public static class ReadLock implements Lock, java.io.Serializable {public void lock() {sync.acquireShared(1); // 共享
    }

    public void unlock() {sync.releaseShared(1); // 共享
    }
}

public static class WriteLock implements Lock, java.io.Serializable {public void lock() {sync.acquire(1); // 独占
    }

    public void unlock() {sync.release(1); // 独占
    }
}

abstract static class Sync extends AbstractQueuedSynchronizer {}

看到这里发现了 ReentrantReadWriteLock 和 ReentrantLock 的一个相同点和不同点,
雷同的是应用了同一个要害实现 AbstractQueuedSynchronizer,不同的是 ReentrantReadWriteLock 应用了两个锁别离实现了 AQS,
而且 WriteLock 和 ReentrantLock 一样,应用了独占锁。

而 ReadLock 和 Semaphore 一样,应用了共享锁。

再往下的内容预计看过后面几篇文章的都很相熟了,独占锁通过 state 变量的 0 和 1 两个状态来管制是否有线程占有锁,共享锁通过 state 变量 0 或者非 0 来管制多个线程拜访。

在下面的代码中,ReadLock 和 WriteLock 应用了同一个 AQS,那么在 ReentrantReadWriteLock 中又是怎么管制读锁和写锁关系的呢?

这当中还有一个问题,因为 16 位最大全 1 示意为 65535,所以读锁和写锁最多能够获取 65535 个。

ReentrantReadWriteLock 会产生写饥饿的状况吗?如果产生,有没有比拟好的解决办法?

ReentrantReadWriteLock 也会产生写申请饥饿的状况,因为写申请一样会排队,
不论是偏心锁还是非偏心锁,在有读锁的状况下,都不能保障写锁肯定能获取到,这样只有读锁始终占用,就会产生写饥饿的状况。
那么 JDK 就没有提供什么好方法来解决这个问题吗?
当然是有的,那就是 JDK8 中新增的改良读写锁 —StampedLock.

本文由猿必过 YBG 公布

退出移动版