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

一开始是开着张孝祥的视频学的,发现了小问题并改正了。代码中做了比较详细的注释。

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

你可能感兴趣的:(一个非常简单的缓冲—使用Java5提供的读写锁处理多线程操作)