高并发流水号的设计与实现(二)

前一篇文章“高并发流水号的设计与实现”中已经完成了一大半了,然后博主就在思考,Version的生命周期应该是怎么样的。假设Version的生命周期在方法内,每次调用的时候Version v = new Version();这样就失去了线程之间共享的目的,所以在方法级别是不可行的。那么放在类的内部变量上,又破外原有的结构,所以就想建立一个新的类VersionProvider来对Version进行统一的管理。在VersionProvider内部使用HashMap来作为Version的容器,业务类型作为map的key。客户端调用时传进业务类型,VersionProvider判断map中是否有对应的Version,有则直接提供生成流水号,没有先建立Version对象,并存入map中。

这样是解决了生成流水号的问题,但假如version对象使用完后长时间为使用,这块内存却不能被回收!这就造成了内存泄露。

第一个想法是使用软引用,private static Map> container = null; 软引用在内存充足的时候并不会被回收,直到内存不足才被垃圾回收,所以这个想法不靠谱,遂放弃之。

第二个想法是,当version对象的流水号使用到最大值后,有两个选择。一,再到数据库中取号,试用高并发情况。二,移除对象,让垃圾回收。

两个想法都实现了,首先改造version。让其成为观察者的目标,在流水号用尽事件发生后,通知观察者。建立两个观察者,一个收到更新通知时,调用version再到数据库中取号;另一个则是把version从容器map中移除,以便能够进行垃圾回收。

改造后的Version代码:

public class Version extends Observable{

	private String btype;
	
	private long maxVal;
	
	private int step;

	private AtomicLong currVal;

	private ReentrantReadWriteLock lock = null;
	
	/**
	 * 构造方法
	 */
	public Version(String btype, Observer o){
		this.btype = btype;
		this.maxVal = 0l;
		this.currVal = new AtomicLong(0);
		this.lock = new ReentrantReadWriteLock();
		this.addObserver(o);
	}
	
	public String getBtype() {
		return btype;
	}

	public void setBtype(String btype) {
		this.btype = btype;
	}

	/**
	 * 
	 * 获取版本
	 * 
	 * @return 版本号
	 */
	public String getVersion() {
		String version = "";
		try {
			// 共享读锁
			lock.readLock().lock();
			if (checkVal()) {
				version = String.valueOf(currVal.getAndAdd(1));
			}else {
				lock.readLock().unlock();
				// 排它写锁
				lock.writeLock().lock();
				try {
					getVersionFromDB();
					version = String.valueOf(currVal.getAndAdd(1));
				} catch (Exception e) {
					e.printStackTrace();
				}finally{
					lock.writeLock().unlock();
				}
				lock.readLock().lock();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lock.readLock().unlock();
		}
		if (!checkVal()) {
			notifyObservers();
		}
		return version;
	}

	/**
	 * 
	 * 检查版本号是否可用
	 * 
	 * @return 成功或者失败
	 */
	private boolean checkVal() {
		return maxVal > currVal.get();
	}

	/**
	 * 从数据库中取出可用版本号
	 */
	public void getVersionFromDB() {
		Long dbVersion = Util.getVersionFromDB(this.btype);
		// 设置当前值
		currVal.set(dbVersion);
		step = 10;
		maxVal = dbVersion + step;
	}

创建两种类型的观察者:ClearVersionObserver用于移除map中的对象,CarryOnVersionObserver用于再次从数据库中取数。

public class ClearVersionObserver implements Observer {

	public void update(Observable o, Object arg) {
		
		Version v = (Version)o;
		VersionProvider.clearVersion(v.getBtype());
	}
	
}
public class CarryOnVersionObserver implements Observer {

	public void update(Observable o, Object arg) {
		Version v = (Version)o;
		v.getVersionFromDB();
	}

}

再创建VersionProvider 用来管理version对象。

public class VersionProvider {

	private static Map container = new ConcurrentHashMap();

	public static String getVersion(String btype) {
		return "";
	}
	
	public static String getVersionSofttCache(String btype){
		
		if (!container.containsKey(btype)) {
			Version version = new Version(btype,new ClearVersionObserver());
			container.put(btype, version);
		}
		return container.get(btype).getVersion();
	}

	public static String getVersionCache(String btype){
		
		if (!container.containsKey(btype)) {
			Version version = new Version(btype,new CarryOnVersionObserver());
			container.put(btype, version);
		}
		return container.get(btype).getVersion();
	}
	
	public static void clearVersion(String btype){
		container.remove(btype);
	}
	
}




你可能感兴趣的:(Java)