读写锁
Java内置了读写锁工具类,方便开发人员针对“读多写少”的场景提升加锁的性能。
为什么需要读写锁?
synchronized和ReentrantLock都属于排他锁,存在明显的性能问题:读读互斥。
当某一个线程获取锁时,其他线程全部阻塞,性能不高。
读写锁可以实现:读读不互斥,仅读写、写写互斥。
对于“读多写少”的场景,允许多个读线程同时操作资源,可以大大提升应用性能。
功能定义
加读锁时,允许其他线程继续加读锁,写锁会被阻塞。
加写锁时,其他线程不管加读锁还是写锁都会被阻塞。
ReadWriteLock接口
ReadWriteLock维护了一个读锁和一个写锁。
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
}
使用示例
使用其子类ReentrantReadWriteLock即可。
/**
* @Author: 潘
* @Date: 2019/11/22 14:30
* @Description: ReentrantReadWriteLock例子
*/
public class ReadWriteLockDemo {
private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
int index = 0;
void writeFunc(){
reentrantReadWriteLock.writeLock().lock();
SleepUtil.sleep(1000);
System.out.println(++index);
reentrantReadWriteLock.writeLock().unlock();
}
void readFunc(){
reentrantReadWriteLock.readLock().lock();
SleepUtil.sleep(3000);
System.out.println(index);
reentrantReadWriteLock.readLock().unlock();
}
public static void main(String[] args) {
ReadWriteLockDemo demo = new ReadWriteLockDemo();
//先加读锁,3s后读锁释放,写锁才能竞争成功
demo.readFunc();
for (int i = 0; i < 10; i++) {
new Thread(()->{
demo.writeFunc();
}).start();
}
}
}
自己实现读写锁
手痒痒,现在看到啥好玩的都想自己手写实现一遍,以便更好的理解。
笔者浅见,可能存在bug,望各位大佬指出。
/**
* @Author: 潘
* @Date: 2019/11/21 20:40
* @Description: 自己实现Java读写锁(不考虑锁的重入)
*/
public class MyReadWriteLock {
private final ReadLock readLock = new ReadLock();
private final WriteLock writeLock = new WriteLock();
//读锁队列
private ConcurrentLinkedQueue<Thread> readQueue = new ConcurrentLinkedQueue<>();
//读锁等待队列
private ConcurrentLinkedQueue<Thread> readWaitQueue = new ConcurrentLinkedQueue<>();
//当前写锁线程
private AtomicReference<Thread> currentWrite = new AtomicReference<>();
//写锁等待队列
private ConcurrentLinkedQueue<Thread> writeWaitQueue = new ConcurrentLinkedQueue<>();
//获取读锁
public ReadLock readLock(){
return readLock;
}
//获取写锁
public WriteLock writeLock(){
return writeLock;
}
//读锁
class ReadLock{
//内部锁标记
private AtomicBoolean innerLock = new AtomicBoolean(false);
void lock(){
//SleepUtil.sleep(10);
while (!innerLock.compareAndSet(false, true)) {
//Thread.yield();
SleepUtil.sleep(1);
}
//当前有写锁或写锁等待队列不为空,优先处理写锁
if (currentWrite.get() != null || !writeWaitQueue.isEmpty()) {
readWaitQueue.add(Thread.currentThread());
LockSupport.park();
}
//读锁竞争成功
readQueue.add(Thread.currentThread());
innerLock.set(false);
System.out.println("read lock");
}
void unlock(){
readQueue.remove(Thread.currentThread());
innerLock.set(false);
if (!readWaitQueue.isEmpty()) {
//读锁等待队列不为空,唤醒
LockSupport.unpark(readWaitQueue.poll());
} else if (readQueue.isEmpty() && readWaitQueue.isEmpty()) {
//读锁全部释放,且没有读锁等待,唤醒写锁等待队列
LockSupport.unpark(writeWaitQueue.poll());
}
System.out.println("read unlock");
}
}
//写锁
class WriteLock{
//内部锁标记
private AtomicBoolean innerLock = new AtomicBoolean(false);
void lock(){
//SleepUtil.sleep(10);
while (!innerLock.compareAndSet(false, true)) {
writeWaitQueue.add(Thread.currentThread());
LockSupport.park();
}
//当前没有读锁和写锁,才能加写锁
if (readQueue.isEmpty() && currentWrite.get() == null) {
currentWrite.set(Thread.currentThread());
System.out.println("write lock");
return;
}
writeWaitQueue.add(Thread.currentThread());
LockSupport.park();
}
void unlock(){
currentWrite.set(null);
innerLock.set(false);
if (!writeWaitQueue.isEmpty()) {
LockSupport.unpark(writeWaitQueue.poll());
System.out.println("write unlock");
return;
}
LockSupport.unpark(readWaitQueue.poll());
System.out.println("write unlock");
}
}
}