java 读写互斥Lock 实现缓存技术

小乞丐 发布于 2013/09/05 15:51
阅读 692
收藏 1
package cn.test;

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

public class CacheDemo {
	private static ReadWriteLock rwl = new ReentrantReadWriteLock(); //读写锁
	private static Map<String, Object> cache = new HashMap<String, Object>();
	public static void main(String[] args) {
		for(int j=0;j<10;j++){ //写入
			final String key= "key"+j;
			new Thread(new Runnable() {
				public void run() {
					 put(key,key);
				}
			}).start();
			new Thread(new Runnable() { //读取
				public void run() {
					Object data = getData(key);
					System.out.println(Thread.currentThread().getName()+"-- get data : {key:"+key+",value: "+data+"}");
				}
			}).start();
		}
	}
	//取
	public  static Object getData(String key){
		rwl.readLock().lock();
		Object value = null;
		try{
			value = cache.get(key);
			if(value == null){
				rwl.readLock().unlock();
				rwl.writeLock().lock();
				try{
					if(value==null){
						value = "no";//实际失去queryDB();
					}
				}finally{
					rwl.writeLock().unlock();
				}
				rwl.readLock().lock();
			}
		}finally{
			rwl.readLock().unlock();
		}
		return value;
	}
	//存
	public static void put(String key,Object value){
		rwl.writeLock().lock();
		System.out.println("begin of put data >>");
		try{
			Thread.sleep(1000);
			if(key != null){
				cache.put(key, value);
			}
			System.out.println(Thread.currentThread().getName()+"-- put data :  {key:"+key+",value: "+value+"}");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.writeLock().unlock();
		}
		System.out.println("end of put data >>");
	}
}
打印结果:   在向缓存中写入数据的时候,读取缓存的线程应该等待 写入锁释放之后才进行读取才对。
 也就是说,打印结果应该是:
     begin of put data >>
     Thread-0-- put data :  {key:key0,value: key0}
     end of put data >>
     Thread-3-- get data : {key:key0,value: key0}
 才对。不知道以上代码哪里出问题了。还请大家帮我看看。
 
 谢谢~~
      
 
加载中
0
sdzzboy
sdzzboy
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class sss {
	private static ReadWriteLock rwl = new ReentrantReadWriteLock(); // 读写锁
	private static Map<String, Object> cache = new HashMap<String, Object>();

	public static void main(String[] args) {
		for (int j = 0; j < 10; j++) { // 写入
			final String key = "key" + j;
			new Thread(new Runnable() {
				public void run() {
					put(key, key);
				}
			}).start();
			new Thread(new Runnable() { // 读取
						public void run() {
							Object data = getData(key);
							
						}
					}).start();
		}
	}

	// 取
	public static Object getData(String key) {
		rwl.readLock().lock();
		Object value = null;
		try {
			value = cache.get(key);
			if (value == null) {
				try {
					if (value == null) {
						value = "no";// 实际失去queryDB();
					}
				} finally {
				}
			}
			System.out.println(Thread.currentThread().getName()
					+ "-- get data : {key:" + key + ",value: "
					+ value + "}");
		} finally {
			rwl.readLock().unlock();
		}
		return value;
	}

	// 存
	public static void put(String key, Object value) {
		rwl.writeLock().lock();
		System.out.println(Thread.currentThread().getName()+" begin of put data >>");
		try {
			Thread.sleep(1000);
			if (key != null) {
				cache.put(key, value);
			}
			System.out.println(Thread.currentThread().getName()
					+ "-- put data :  {key:" + key + ",value: " + value + "}");
			System.out.println("end of put data >>");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			rwl.writeLock().unlock();
		}
		
	}
}
不知道这么写是不是想要的效果
 
1
mallon
mallon
ConcurrentHashMap
0
小乞丐
小乞丐

上面问题的图片


0
Sub
Sub
rwl.readLock().unlock();
rwl.writeLock().lock();


这样的写法是有问题的,不能保证线程的连续执行。除非你用另外一个 lock 来保证原子性。 
同时 ReadWriteLock 也不支持 read 升级为 write

0
Sub
Sub
而且 如果  queryDB throw exception 的时候,最后的那个 finally 里面的  rwl.readLock().unlock(); 会出问题,因为根本就没有 readlock
0
小乞丐
小乞丐

引用来自“Sub”的答案

rwl.readLock().unlock();
rwl.writeLock().lock();


这样的写法是有问题的,不能保证线程的连续执行。除非你用另外一个 lock 来保证原子性。 
同时 ReadWriteLock 也不支持 read 升级为 write

我先把读锁unlock掉。然后在加上一个写锁。这么写没问题的呀。
0
小乞丐
小乞丐

引用来自“专业打酱油”的答案

1、你要求读写互斥

2、你的存方法put只有写锁,而没有读锁,明显不符合你的要求。

3、你下面说的应该是这样的例子,其实也是不一定的!

4、你说的读写互斥,仅仅是对于map的put和get是互斥的。

5、目前你的线程执行顺序是不可控的,有可能出现no的情况,因为取得时候,可能还没放进去。

如果在写方法中加上读锁,用的都是同一个lock对象,会不会就对写锁降级了呢?

就像这样改写方法:

//存
	public static void put(String key,Object value){
		rwl.writeLock().lock();
		rwl.readLock().lock();
		System.out.println("begin of put data >>");
		try{
			Thread.sleep(1000);
			if(key != null){
				cache.put(key, value);
			}
			System.out.println(Thread.currentThread().getName()+"-- put data :  {key:"+key+",value: "+value+"}");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			rwl.readLock().unlock();
			rwl.writeLock().unlock();
		}
		System.out.println("end of put data >>");
	}

得到的结果是:

begin of put data >>
Thread-0-- put data :  {key:key0,value: key0}
end of put data >>
begin of put data >>
Thread-1-- get data : {key:key0,value: key0}
Thread-2-- put data :  {key:key1,value: key1}
end of put data >>
Thread-3-- get data : {key:key1,value: key1}
Thread-5-- get data : {key:key2,value: no}
begin of put data >>
Thread-6-- put data :  {key:key3,value: key3}
begin of put data >>
end of put data >>
Thread-4-- put data :  {key:key2,value: key2}
end of put data >>
Thread-7-- get data : {key:key3,value: key3}
begin of put data >>
Thread-8-- put data :  {key:key4,value: key4}
end of put data >>
Thread-9-- get data : {key:key4,value: key4}
begin of put data >>
Thread-10-- put data :  {key:key5,value: key5}
Thread-11-- get data : {key:key5,value: key5}
begin of put data >>
end of put data >>
Thread-12-- put data :  {key:key6,value: key6}
end of put data >>
Thread-13-- get data : {key:key6,value: key6}
begin of put data >>
Thread-14-- put data :  {key:key7,value: key7}
Thread-15-- get data : {key:key7,value: key7}
begin of put data >>
end of put data >>
Thread-16-- put data :  {key:key8,value: key8}
end of put data >>
Thread-17-- get data : {key:key8,value: key8}
begin of put data >>
Thread-18-- put data :  {key:key9,value: key9}
end of put data >>
Thread-19-- get data : {key:key9,value: key9}

还是会存在这样的情况:

begin of put data >>
Thread-1-- get data : {key:key0,value: key0}
Thread-2-- put data :  {key:key1,value: key1}
end of put data >>



0
小乞丐
小乞丐

引用来自“sdzzboy”的答案

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

public class sss {
	private static ReadWriteLock rwl = new ReentrantReadWriteLock(); // 读写锁
	private static Map<String, Object> cache = new HashMap<String, Object>();

	public static void main(String[] args) {
		for (int j = 0; j < 10; j++) { // 写入
			final String key = "key" + j;
			new Thread(new Runnable() {
				public void run() {
					put(key, key);
				}
			}).start();
			new Thread(new Runnable() { // 读取
						public void run() {
							Object data = getData(key);
							
						}
					}).start();
		}
	}

	// 取
	public static Object getData(String key) {
		rwl.readLock().lock();
		Object value = null;
		try {
			value = cache.get(key);
			if (value == null) {
				try {
					if (value == null) {
						value = "no";// 实际失去queryDB();
					}
				} finally {
				}
			}
			System.out.println(Thread.currentThread().getName()
					+ "-- get data : {key:" + key + ",value: "
					+ value + "}");
		} finally {
			rwl.readLock().unlock();
		}
		return value;
	}

	// 存
	public static void put(String key, Object value) {
		rwl.writeLock().lock();
		System.out.println(Thread.currentThread().getName()+" begin of put data >>");
		try {
			Thread.sleep(1000);
			if (key != null) {
				cache.put(key, value);
			}
			System.out.println(Thread.currentThread().getName()
					+ "-- put data :  {key:" + key + ",value: " + value + "}");
			System.out.println("end of put data >>");
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			rwl.writeLock().unlock();
		}
		
	}
}
不知道这么写是不是想要的效果

没错是这样的哈。。

我也刚好弄出来。

package cn.test;

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

public class CacheDemo {
	private final ReadWriteLock rwl = new ReentrantReadWriteLock(); //读写锁
	private final Lock rl = rwl.readLock();
	private final Lock wl = rwl.writeLock();
	private  Map<String, Object> cache = new HashMap<String, Object>();
	public static void main(String[] args) {
		final CacheDemo support = new CacheDemo();  
		for(int j=0;j<10;j++){ //写入
			final String key= "key"+j;
			new Thread(new Runnable() {
				public void run() {
					support.put(key,key);
				}
			}).start();
			new Thread(new Runnable() { //读取
				public void run() {
					support.getData(key);
				}
			}).start();
		}
	}
	//取
	public  Object getData(String key){
		rl.lock();
		System.out.println("开始读取缓存数据....."+Thread.currentThread().getName()+" - "+System.currentTimeMillis());
		Object value = null;
		try{
			value = cache.get(key);
			if(value == null){
				rl.unlock();
				wl.lock();
				try{
					if(value==null){
						value = "no";//实际失去queryDB();
					}
				}finally{
					wl.unlock();
				}
				rl.lock();
			}
			System.out.println(Thread.currentThread().getName()+"-- 读 : {key:"+key+",value: "+value+"}");
		}finally{
			System.out.println("结束读取缓存数据....."+Thread.currentThread().getName()+" - "+System.currentTimeMillis());
			rl.unlock();
		}
		return value;
	}
	//存
	public void put(String key,Object value){
		wl.lock();
		//rwl.readLock().lock();
		System.out.println("开始写入缓存数据....."+Thread.currentThread().getName()+" - "+System.currentTimeMillis());
		try{
			Thread.sleep(1000);
			if(key != null){
				cache.put(key, value);
			}
			System.out.println(Thread.currentThread().getName()+"-- 写 :  {key:"+key+",value: "+value+"}");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally{
			//rwl.readLock().unlock();
			System.out.println("结束写入缓存数据....."+Thread.currentThread().getName()+" - "+System.currentTimeMillis());
			wl.unlock();
		}
		
	}
}
开始写入缓存数据.....Thread-0 - 1378392303555
Thread-0-- 写 :  {key:key0,value: key0}
结束写入缓存数据.....Thread-0 - 1378392304555
开始读取缓存数据.....Thread-1 - 1378392304556
开始读取缓存数据.....Thread-3 - 1378392304556
Thread-1-- 读 : {key:key0,value: key0}
结束读取缓存数据.....Thread-1 - 1378392304556
开始写入缓存数据.....Thread-2 - 1378392304557
Thread-2-- 写 :  {key:key1,value: key1}
结束写入缓存数据.....Thread-2 - 1378392305557
开始写入缓存数据.....Thread-4 - 1378392305557
Thread-4-- 写 :  {key:key2,value: key2}
结束写入缓存数据.....Thread-4 - 1378392306557
开始读取缓存数据.....Thread-5 - 1378392306557
Thread-5-- 读 : {key:key2,value: key2}
结束读取缓存数据.....Thread-5 - 1378392306557
开始写入缓存数据.....Thread-6 - 1378392306557
Thread-6-- 写 :  {key:key3,value: key3}
结束写入缓存数据.....Thread-6 - 1378392307557
开始读取缓存数据.....Thread-7 - 1378392307557
Thread-7-- 读 : {key:key3,value: key3}
结束读取缓存数据.....Thread-7 - 1378392307557
开始写入缓存数据.....Thread-8 - 1378392307557
Thread-8-- 写 :  {key:key4,value: key4}
结束写入缓存数据.....Thread-8 - 1378392308557
开始读取缓存数据.....Thread-9 - 1378392308557
Thread-9-- 读 : {key:key4,value: key4}
结束读取缓存数据.....Thread-9 - 1378392308558
开始写入缓存数据.....Thread-10 - 1378392308558
Thread-10-- 写 :  {key:key5,value: key5}
结束写入缓存数据.....Thread-10 - 1378392309558
开始读取缓存数据.....Thread-11 - 1378392309558
Thread-11-- 读 : {key:key5,value: key5}
结束读取缓存数据.....Thread-11 - 1378392309558
开始写入缓存数据.....Thread-12 - 1378392309558
Thread-12-- 写 :  {key:key6,value: key6}
结束写入缓存数据.....Thread-12 - 1378392310558
开始读取缓存数据.....Thread-13 - 1378392310558
Thread-13-- 读 : {key:key6,value: key6}
结束读取缓存数据.....Thread-13 - 1378392310558
开始写入缓存数据.....Thread-14 - 1378392310558
Thread-14-- 写 :  {key:key7,value: key7}
结束写入缓存数据.....Thread-14 - 1378392311559
开始读取缓存数据.....Thread-15 - 1378392311559
Thread-15-- 读 : {key:key7,value: key7}
结束读取缓存数据.....Thread-15 - 1378392311559
开始写入缓存数据.....Thread-16 - 1378392311559
Thread-16-- 写 :  {key:key8,value: key8}
结束写入缓存数据.....Thread-16 - 1378392312559
开始读取缓存数据.....Thread-17 - 1378392312559
Thread-17-- 读 : {key:key8,value: key8}
结束读取缓存数据.....Thread-17 - 1378392312559
开始写入缓存数据.....Thread-18 - 1378392312559
Thread-18-- 写 :  {key:key9,value: key9}
结束写入缓存数据.....Thread-18 - 1378392313559
开始读取缓存数据.....Thread-19 - 1378392313559
Thread-19-- 读 : {key:key9,value: key9}
结束读取缓存数据.....Thread-19 - 1378392313559
Thread-3-- 读 : {key:key1,value: no}
结束读取缓存数据.....Thread-3 - 1378392313559

返回顶部
顶部