关于读写锁-ReentrantReadWriteLock

读写锁 ReentrantReadWriteLock,其核心就是实现 读写分离,多哦,突然记得之前学的COW容器也是读写分离的。好了,读写分离有什么好处了,就是在高并发访问下,尤其是读多写少的情况下,性能要远高于重入锁。
之前学synchronized、ReentrantLock的时候,我们都知道,同一时间内,只能有一个线程进行访问被锁定的代码,那么读写锁则不同,其本质是分成两个锁,就是读锁和写锁。在读锁下,多个线程可以并发的进行访问,但是在写锁的时候,只能一个一个的访问。只有是读的情况下是可以并发访问的,而多个线程访问写或者多个线程分别访问读和写,都是一个一个地访问的。
有这么一个口诀:读读共享,写写互斥,读写互斥。

1、下面的例子是看如何使用,而且测一下是不是读读共享。
public class UseReentrantReadWriteLock {
	private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
//原来读锁和写锁都是用ReentrantReadWriteLock创建出来的,哪个方法需要什么锁,就调用什么锁的lock()方法,不过最后记得要释放锁。	
private ReadLock rLock = rwLock.readLock(); 
	private WriteLock wLock = rwLock.writeLock();
	
	public void read(){ //读操作
		try{
 //因为这里模拟的是读操作,所以调用的是读锁的lock方法
			rLock.lock(); 
			System.out.println("线程:"+Thread.currentThread().getName()+"进入读操作");
			Thread.sleep(2000);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			System.out.println("线程:"+Thread.currentThread().getName()+"执行完读操作");
			rLock.unlock();
		}
	}
	
	public void write(){ //写操作
		try{
  //因为这里模拟的是写操作,所以调用的是写锁的lock方法。
			wLock.lock();
			System.out.println("线程:"+Thread.currentThread().getName()+"进入写操作");
			Thread.sleep(2000);
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			System.out.println("线程:"+Thread.currentThread().getName()+"执行完写操作");
			wLock.unlock();
		}
	}
	
	public static void main(String[] args) {
		UseReentrantReadWriteLock urLock = new UseReentrantReadWriteLock();
		Thread t1 = new Thread(new Runnable(){

			@Override
			public void run() {
				urLock.read();
			}
			
		},"t1");
		Thread t2 = new Thread(new Runnable(){

			@Override
			public void run() {
				urLock.read();
			}
			
		},"t2");
		
		t1.start();
		t2.start();
	}
}
执行结果:可以发现,线程1和线程2是同时获得读锁然后进入读方法的,也是同时的完成。所以说读读是共享的,不存在单个线程获得锁执行方法的说法。
线程:t2进入读操作
线程:t1进入读操作
线程:t2执行完读操作
线程:t1执行完读操作

2、那么下面是测试写写是否是互斥的。
我们将上面的线程1和线程2都换成调用写操作就可以测试了。
UseReentrantReadWriteLock urLock = new UseReentrantReadWriteLock();
Thread t1 = new Thread(new Runnable(){
	@Override
	public void run() {
		urLock.write();
	}
			
},"t1");
Thread t2 = new Thread(new Runnable(){

	@Override
	public void run() {
		urLock.write();
	}
			
},"t2");
		
t1.start();
t2.start();
执行结果:可以看到,线程2先获取了写锁然后执行写方法,当线程2执行完释放锁后,线程1才获得写锁然后执行写操作。所以说写写是互斥的。
线程:t2进入写操作
线程:t2执行完写操作
线程:t1进入写操作
线程:t1执行完写操作

3、最后看一下读写互斥,我们将线程1改为读操作,线程2是写操作。
UseReentrantReadWriteLock urLock = new UseReentrantReadWriteLock();
Thread t1 = new Thread(new Runnable(){

	@Override
	public void run() {
		urLock.read();
	}
			
},"t1");
Thread t2 = new Thread(new Runnable(){

	@Override
	public void run() {
		urLock.write();
	}
			
},"t2");
		
t1.start();
t2.start();
执行结果:我们可以看到,写操作和读操作确实是互斥的,只有其中一个操作做完,另一个操作才能进行。
线程:t2进入写操作
线程:t2执行完写操作
线程:t1进入读操作
线程:t1执行完读操作
读写锁还挺有意思的。。

猜你喜欢

转载自blog.csdn.net/howinfun/article/details/80872760