读写锁的使用
读写锁在 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 发布
禁止未经授权转载,违者依法追究相关法律责任
如需授权可联系:zhuyunhui@yuanbiguo.com
网友评论