1. 程式人生 > >多執行緒學習----讀寫鎖的使用(十二)

多執行緒學習----讀寫鎖的使用(十二)

讀寫鎖

     讀寫鎖:分為讀鎖和寫鎖,多個讀鎖不互斥,讀鎖與寫鎖互斥,寫鎖和寫鎖互斥,這是由jvm自己控制的,你只要上好相應的鎖即可。如果你的程式碼只讀資料,可以很多人同時讀,但是不能同時寫,那就讓讀鎖;如果你的程式碼修改資料,只能有一個人在寫,且不能同時讀取,那就上寫鎖。總之,讀的時候上讀鎖,寫的時候上寫鎖!

讀寫鎖的應用:

假設開啟三個執行緒寫資料,三個執行緒讀資料(讀讀不互斥,讀寫互斥,寫寫互斥)

public class ReadWriteLockStudy {

	
	public static void main(String[] args) {
		ReadAndWrite raw = new ReadAndWrite();
		for(int i = 0;i < 3;i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
					raw.get();//讀
				}
			}).start();
			new Thread(new Runnable() {
				@Override
				public void run() {
					raw.set(Math.random()*1000);//寫
				}
			}).start();
		}
	}
	
}
class ReadAndWrite{
	private Object data = null;
	ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
	public void get(){
		readWriteLock.readLock().lock();;
		System.out.println(Thread.currentThread().getName()+" be ready to read");
		try {
			Thread.sleep((long)Math.random()*1000);
			System.out.println(Thread.currentThread().getName()+" has read data:"+data);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			readWriteLock.readLock().unlock();
		}
		
	}
	public void set(Object data){
		readWriteLock.writeLock().lock();
		try {
			System.out.println(Thread.currentThread().getName()+" be ready to write");
			Thread.sleep((long)Math.random()*1000);
			this.data = data;
			System.out.println(Thread.currentThread().getName()+" has write data:"+this.data);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			readWriteLock.writeLock().unlock();
		}
		
	}
}

面試題:寫一個快取系統的虛擬碼

public class CacheDemoStudy {

	private  Map<String,Object> cache = new HashMap<String,Object>();
	public static void main(String[] args) {
		final CacheDemoStudy cacheDemoStudy = new CacheDemoStudy();
		for(int i = 0;i < 5;i++){
			new Thread(new Runnable() {
				@Override
				public void run() {
						System.out.println(Thread.currentThread().getName()+"拿到資料"+cacheDemoStudy.getData("dataKey"));
				}
			}).start();
		}
	}
	
	private ReadWriteLock rwl = new ReentrantReadWriteLock();
	public  Object getData(String key){
		rwl.readLock().lock();
		try{
			System.out.println(Thread.currentThread().getName()+"去拿資料");
			if(cache.get(key) == null){
				System.out.println(Thread.currentThread().getName()+"沒有拿到資料");
			}
			if(cache.get(key) == null){
				rwl.readLock().unlock();
				rwl.writeLock().lock();
				try{
					if(cache.get(key) == null){
						System.out.println(Thread.currentThread().getName()+"去寫資料");
						cache.put("dataKey", "aaaaa");
					}
				}finally{
					rwl.writeLock().unlock();
				}
				rwl.readLock().lock();
			}
		}finally {
			rwl.readLock().unlock();
		}
		return cache.get(key);
	}
}

執行結果:

只去寫了一次資料