(多线程与并发)面试题03--java中读写锁ReadWriteLock

Posted 架构师夏老师

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(多线程与并发)面试题03--java中读写锁ReadWriteLock相关的知识,希望对你有一定的参考价值。

1.排他锁(互斥锁)的概念:

       synchronized,ReentrantLock这些锁都是排他锁,这些锁同一时刻只允许一个线程进行访问。

2.读写锁的概念:

       分为读锁和写锁,多个读锁不互斥,读锁和写锁互斥,写锁与写锁互斥。

3.读写锁的好处:

为了提高性能,Java提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,如果没有写锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率。

       原来使用的互斥锁只能同时间有一个线程在运行,现在的读写锁同一时刻可以多个读锁同时运行,这样的效率比原来的排他锁(互斥锁)效率高

       

4.读写锁的原理分析:

    Java中读写锁有个接口java.util.concurrent.locks.ReadWriteLock,也有具体的实现ReentrantReadWriteLock,

     lock方法 是基于CAS 来实现的

   

源码:

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();


5.案例一:

package WriteReadLock;

import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class ReadWriterLockTest 
	public static void main(String[] args) 
		final Queue q3 = new Queue();
		for(int i=0;i<3;i++)
		
			new Thread()
				public void run()
					while(true)
						q3.get();						
					
				
				
			.start();
		
		for(int i=0;i<3;i++)
				
			new Thread()
				public void run()
					while(true)
						q3.put(new Random().nextInt(10000));
					
							
				
			.start();
   
	



class Queue
	//共享数据,只能有一个线程能写该数据,但可以有多个线程同时读该数据。
	private Object data = null;
	//得到读写锁
	ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	
	/**
     * 将用于读的get()和写的put()放在同一个类中这样是为了对同一个资源data进行操作,形成互斥
     */
	
	/**
	 * 进行读操作
	 * 可以多个读线程同时进入,写线程不能执行
	 */
	public void get()
		//获取读锁,并加锁
		Lock readLock = readWriteLock.readLock();
		readLock.lock();
		try 
			System.out.println(Thread.currentThread().getName() + " be ready to read data!");
			Thread.sleep((long)(Math.random()*1000));
			System.out.println(Thread.currentThread().getName() + "have read data :"+ data);		
			
		 catch (InterruptedException e) 
			e.printStackTrace();
		finally 
			//!!!!!!注意:锁的释放一定要在trycatch的finally中,因为如果前面程序出现异常,锁就不能释放了
			//释放读锁
			readLock.unlock();
		

		
	
	
	/**
	 * 进行写操作
	 * 只能一个写线程进入,读线程不能执行
	 */
	public void put(Object data)
		//获取写锁,并加锁
		Lock writeLock = readWriteLock.writeLock();
		writeLock.lock();
		try 
			System.out.println(Thread.currentThread().getName() + " be ready to write data!");					
			Thread.sleep((long)(Math.random()*1000));
			this.data = data;		
			System.out.println(Thread.currentThread().getName() + " have write data: " + data);	
			
		 catch (InterruptedException e) 
			e.printStackTrace();
		finally 
			//释放写锁
			writeLock.unlock();
		
		
	


没有使用锁之前:读和写交叉在一起


在加入读写锁之后:读的过程中,不会有写


6.案例二:

package WriteReadLock;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class CacheDemo 
	//用map来模拟缓存
	Map<String,Object> cache = new HashMap<String,Object>();
	ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

	
	public static void main(String[] args) 
		final CacheDemo cacheDemo = new CacheDemo();
		for(int i=0;i<6;i++)
		
			new Thread()
				public void run()
					while(true)
					
						System.out.println(	cacheDemo.getData("key1").toString());
					
				
				
			.start();
		
		
	
	
	
	Lock readLock = readWriteLock.readLock();
	Lock writeLock = readWriteLock.writeLock();
	//这里必须要用volatie当一个写线程设置value="aaaabbbb",一定要让其他的线程知道vlue的变化,这样就不会被重复写
	volatile Object value;
	public Object getData(String key)
		
		readLock.lock();
		
		try 
			Thread.sleep(300);
			System.out.println(" read");
		  	 value = cache.get(key);
			if (value == null) 
				
				//这里已经加了读锁,读锁中写是不能允许的,所以要把这个锁释放掉
				readLock.unlock();
				writeLock.lock();
				//防止,当多个写者进程在等待,前面的写进程已经赋值了,value已经不为空了后面的等着的写进程仍然继续赋值
				if(value == null)
					System.out.println("find null");
				  
					value="aaaabbbb";
					cache.put(key, value);
					System.out.println("write");
				
				
				
				writeLock.unlock();
				//从新加上读锁
				readLock.lock();
				
			
			return value;
			
		 catch (Exception e) 
			e.printStackTrace();
		finally 
			readLock.unlock();
		

		return null;
	
	
	








以上是关于(多线程与并发)面试题03--java中读写锁ReadWriteLock的主要内容,如果未能解决你的问题,请参考以下文章

多线程面试题系列(14):读者写者问题继 读写锁SRWLock

IOS面试题(多线程) --- 锁

Java多线程Java面试题

Java多线程Java面试题

交易系统开发技能之并发编程面试题

19年BAT常问面试题汇总:JVM+微服务+多线程+锁+高并发性能