读写锁以及手写实现

读写锁

Java内置了读写锁工具类,方便开发人员针对“读多写少”的场景提升加锁的性能。

为什么需要读写锁?

synchronizedReentrantLock都属于排他锁,存在明显的性能问题:读读互斥。
当某一个线程获取锁时,其他线程全部阻塞,性能不高。

读写锁可以实现:读读不互斥,仅读写、写写互斥。

对于“读多写少”的场景,允许多个读线程同时操作资源,可以大大提升应用性能。

功能定义

加读锁时,允许其他线程继续加读锁,写锁会被阻塞。
加写锁时,其他线程不管加读锁还是写锁都会被阻塞。

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");
		}
	}
}
发布了100 篇原创文章 · 获赞 23 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_32099833/article/details/103206459