一个非常简单的缓冲—使用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(); } } }
相关文章推荐
- 使用EF6和MVC5实现一个简单的选课系统--使用EF6处理并发操作(10/12)
- 异常信息:CLR无法从COM 上下文0x645e18 转换为COM上下文0x645f88,这种状态已持续60秒。拥有目标上下文/单元的线程很有可能执行的是非泵式等待或者在不发送 Windows 消息的情况下处理一个运行时间非常长的操作.这种情况通常会影响到性能,甚至可能导致应用程序不响应或者使用的内存随时间不断累积
- 这是一个秒杀系统,即大量用户抢有限的商品,先到先得 用户并发访问流量非常大,需要分布式的机器集群处理请求 系统实现使用Java
- Java【多线程知识总结(6)】使用Runnable接口创建多线程,处理同一个资源
- 使用Java开发一个非常简单的Web Service例子
- Java【多线程知识总结(6)】使用Runnable接口创建多线程,处理同一个资源
- 在Java中使用多线程结合断点续传实现一个简单的文件下载器
- 多线程(三) java中线程的简单使用
- 一个基于Java的简单分组处理算法
- (一)使用IDEA新建一个最简单的JavaWeb项目,Maven管理
- 使用 java 实现一个简单的 markdown 语法解析器
- java 使用线程做一个简单的ATM存取款实例.(转)
- 使用阿里大于接口实现一个简单的短信验证(Java版)
- 使用Java8的Lambda实现的一个简单案例
- 数据库---简单的使用Java操作数据库增删改查
- XP中java swing 在中文输入的时候总有一个输入窗口,非常难看,可以采用此种方法处理
- 使用多线程模拟多用户并发访问一个或多个tomcat,测试性能 java
- Java:多线程,线程池,使用CompletionService通过Future来处理Callable的返回结果
- Java多线程之~~~使用CountDownLatch来同步多个线程实现一个任务
- Resin是CAUCHO公司的产品,是一个非常流行的application server,对servlet和JSP提供了良好的支持,性能也比较优良,resin自身采用JAVA语言开发。