前一篇文章“高并发流水号的设计与实现”中已经完成了一大半了,然后博主就在思考,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代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78public 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用于再次从数据库中取数。
1
2
3
4
5
6public class ClearVersionObserver implements Observer { public void update(Observable o, Object arg) { Version v = (Version)o; VersionProvider.clearVersion(v.getBtype()); } }
1
2
3
4
5
6
7public class CarryOnVersionObserver implements Observer { public void update(Observable o, Object arg) { Version v = (Version)o; v.getVersionFromDB(); } }
再创建VersionProvider 用来管理version对象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public 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); } }
最后
以上就是花痴缘分最近收集整理的关于高并发流水号的设计与实现(二)的全部内容,更多相关高并发流水号内容请搜索靠谱客的其他文章。
发表评论 取消回复