您的位置:首页 > 编程语言 > Java开发

一个非常简单的缓冲—使用Java5提供的读写锁处理多线程操作

2012-11-01 23:55 666 查看
一开始是开着张孝祥的视频学的,发现了小问题并改正了。代码中做了比较详细的注释。

package com.clb.util;

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 static int sequence = 0;
private Map<String, Object> map = new HashMap<String, Object>();
private ReadWriteLock rwLock = new ReentrantReadWriteLock();	//读写锁
private Lock readLock = rwLock.readLock();		//读锁
private Lock writeLock = rwLock.writeLock();	//写锁

public Object getData(String key)
{
if (key == null || "".equals(key))
{
return null;
}

/*
* Java5中新引入的读写锁,因为读取操作不会改变共享的变量的值,所以多个线程可以同时进行数据的读取。
* 也就是说读锁是不互斥的。
*/
rwLock.readLock().lock();
Object value = map.get(key);
try
{
//value值为null说明还没被缓存,这个时候就需要将对value进行一个赋值的操作,很明显的写入
if (value == null)
{
try
{
/*
* 因为读和写是互斥的,在前面获得的读锁,如果不及时的释放,写锁是无法获取到的。
* 所以这边的步骤是:1.unlock读锁 2.获取写锁
* 如果上述的两个步骤呼唤一下会怎么样呢?
* 从写着的代码中来看,写锁要去获得锁,但是前面的读锁还没释放,因为两者互斥的缘故,
* 写锁将获取不到。所以,从现象看来会一直卡在那里的,传说中的死锁
*
* 另外这两句话其实我觉得包含的东西非常的多。来描述一下场景:
* 在程序运行的开始value==null的时候,会有多个线程都会获得读锁,然后顺着代码
* 走到readLock.unlock();  这一句之后所有的读锁都被释放了,释放最快的那个线程
* 将会获得写锁。因为写锁跟写所之间是互斥的。所以最快的线程获得了写所后,其他
* 的线程都处于休眠状态(lock方法的api这么说的),直到把写锁释放掉后。又开始抢写锁,
* 抢到的运行下去,没抢到的继续睡。
*/
readLock.unlock();
writeLock.lock();

/*
* 要讲一下这边 为什么有这个while循环
* 上面的writeLock.lock()方法会导致有多个线程休眠。
* 第一个线程执行此方法后,这个value就不会是value了。
* 第一个线程将写锁释放后,原来休眠的线程抢到了写锁,往下执行,
* 如果没有这个while判断条件(其实if也可以),那里面的操作再次会被执行,这不是我们想要的
*
* 在while中再去判断是否为null,这样就完美了
*/
while (map.get(key) == null)
{
//模拟数据库查询操作并存到map中
value = query();
map.put(key, value);
}
}
finally
{
/*
* 每一个取锁和解锁的过程都应该放在try{}finally语句块中位防止在代码运行过程中出错而导致锁没有被释放的
* 情况。一旦出现了,那就死锁了
*/
rwLock.writeLock().unlock();
rwLock.readLock().lock();
}
}
}
finally
{
rwLock.readLock().unlock();
}

return value;
}

/**
* 模拟耗时的数据库查询
* @return
*/
private Object query()
{
try
{
Thread.sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}

return ++sequence;
}

public static void main(String[] args)
{
final CacheDemo cache = new CacheDemo();
/*
* 开50个线程去获取数据,够多线程了
*/
for (int i = 0; i < 50; i++)
{
final int count = i;
new Thread(new Runnable()
{
@Override
public void run()
{
Object value = cache.getData(count + "");
System.out.println("value" + count + ":" + value);
}
}).start();
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐