概述
前一篇文章“高并发流水号的设计与实现”中已经完成了一大半了,然后博主就在思考,Version的生命周期应该是怎么样的。假设Version的生命周期在方法内,每次调用的时候Version v = new Version();这样就失去了线程之间共享的目的,所以在方法级别是不可行的。那么放在类的内部变量上,又破外原有的结构,所以就想建立一个新的类VersionProvider来对Version进行统一的管理。在VersionProvider内部使用HashMap来作为Version的容器,业务类型作为map的key。客户端调用时传进业务类型,VersionProvider判断map中是否有对应的Version,有则直接提供生成流水号,没有先建立Version对象,并存入map中。
这样是解决了生成流水号的问题,但假如version对象使用完后长时间为使用,这块内存却不能被回收!这就造成了内存泄露。
第一个想法是使用软引用,private static Map<String, SoftReference<Version>> 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<String, Version> container = new ConcurrentHashMap<String, Version>();
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);
}
}
最后
以上就是花痴缘分为你收集整理的高并发流水号的设计与实现(二)的全部内容,希望文章能够帮你解决高并发流水号的设计与实现(二)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复