- 浏览: 26384 次
- 性别:
- 来自: 上海
-
文章分类
最新评论
-
redhat:
stupidly wrong! java proxy has ...
拿到spring proxy的target class -
Agrael:
恩,目前正关注,等把相关资料看一遍再继续。
Google Collections(Guava)中强大的Concurrent MapMaker -
Norther:
Agrael 写道我指的转正是纳入JDK API中。我个人不是 ...
Google Collections(Guava)中强大的Concurrent MapMaker -
Agrael:
我指的转正是纳入JDK API中。我个人不是很喜欢用非标准库里 ...
Google Collections(Guava)中强大的Concurrent MapMaker -
Norther:
Agrael 写道其实我在想,google的collectio ...
Google Collections(Guava)中强大的Concurrent MapMaker
仔细研究了刚发布1.0版本的Google Collections,被其中的MapMaker震惊,这不就是我梦寐以求的Concurrent Map神器吗?如果Google Collection在5年前就发布该有多好?!废话少讲,邀请大家一起来观赏一下什么是MapMaker。
Hashtable太老土啦,线程安全我都用ConcurrentHashMap。什么?现在流行MapMaker?
JDK 1.5引入的ConcurrentHashMap由于其精巧的设计,更高的并发性能,捕获了大家的心,在并发场景中出场率极高,但随着深入的使用,很快的就发现了其中的不足。例如在以Map作为Cache的典型场景中,我们都需要有元素过期的处理,WeakHashMap是这方面的高手,但其在并发方面有点菜(非线程安全),当我们想让这两位大将同时上场的时候,就只能抓耳搔腮了。
Google Collections中的MapMaker融合了Weak Reference,线程安全,高并发性能,异步超时清理,自定义构建元素等强大功能于一身。(注)
常阅读优秀源代码的童鞋都知道,一般叫Maker的对象都是Builder模式,而这个MapMaker就是来"Build"Map的,下面的代码展示了如何构建一个高并发性能,线程安全的WeakHashMap.
是不是够简单?他不仅支持WeakKeys,还支持WeakValues。
还可以选用SoftKeys,和SoftValues,随意组合,比只能WeakKey的WeakHashMap扩展性强太多了。
再来看看On-demand value computation,自定义构建元素。想象下面的场景,你要为一个查询学生信息的DAO增加结果缓存,并且结果超过60秒过期,我们可以用装饰模式结合MapMaker简单的实现。
线程安全,高并发性能,元素过期都实现了,并且代码很简洁。多亏了MapMaker,脏活、累活,就交给它啦。不过要注意的是,要遵循ConcurrentHashMap的规范,其不允许有Null的Key和Value。如果查询出来的结果可能为Null的,可用简单的包装类包装一下,这里不给出代码了。
怎么样?你是不是心动了呢?快下载来看看吧。
注:参考该文章了解是什么WeakReference?http://www.iteye.com/topic/401478
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
没仔细看你的代码, 但请允许我凭臆断说几句大言不惭的话
1. 我不认为你的实现会比 google-collections 优秀, 因为 :
2. 我不认为你的水平会比 Bob Lee 或者 Doug Lea 高
所以
3. 我会在项目里用公认的优秀类库而不会因为自己开心就写一些帮助不大的东西
因为
4. 这会导致项目的维护成本增加
如果我想让别人认可我的作品
5. 如果允许, 我会把它开源让所有的人来试用, 我会写一个 feature list comparison 来比较它跟其他作品, 代码放在那, 孰优孰劣大家心里都会很明白
另外 , 个人认为用中文写注释是一个非常坏的习惯
我并没说和什么相比,我只是说自己多留意一下多用心,很多东西并不是不可能。
我也没和google-collections比,当然我的水平没有 Bob Lee 或者 Doug Lea 高,但是,请先看明白我想说的是什么:)
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
没仔细看你的代码, 但请允许我凭臆断说几句大言不惭的话
1. 我不认为你的实现会比 google-collections 优秀, 因为 :
2. 我不认为你的水平会比 Bob Lee 或者 Doug Lea 高
所以
3. 我会在项目里用公认的优秀类库而不会因为自己开心就写一些帮助不大的东西
因为
4. 这会导致项目的维护成本增加
如果我想让别人认可我的作品
5. 如果允许, 我会把它开源让所有的人来试用, 我会写一个 feature list comparison 来比较它跟其他作品, 代码放在那, 孰优孰劣大家心里都会很明白
另外 , 个人认为用中文写注释是一个非常坏的习惯
我想你是问的我,不是楼主。
上面我就说了,不过我不知道你说的这个类,我看的是Xwork里的一个类,在我new一个实例就创建一个线程困扰的时候,看到那个类后把new一个实例就创建一个线程改为了只会有一个线程,除此之外,这个ReferenceMap已经和我发的代码差不多了。如果有相似的,我估计是思想大同小异吧。
呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。
这个ReferenceMap我修改过无数次,最终形成了现在的版本。
在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。
至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。
你国外的朋友不会是Bob Lee吧?强的!
http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/base/FinalizablePhantomReference.java
绝对不是,而且当时我参考的也不是这个包的东西。
呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。
这个ReferenceMap我修改过无数次,最终形成了现在的版本。
在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。
至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。
你国外的朋友不会是Bob Lee吧?强的!
http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/base/FinalizablePhantomReference.java
呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。
这个ReferenceMap我修改过无数次,最终形成了现在的版本。
在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。
至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
请原谅我的愚钝,这样一行声明不知道想要表达什么意思?
呵呵,可能是我说得不名不白。ReferenceKeyType.WEAK,ReferenceValueType.SOFT构造函数传了这2个枚举进去,KEY为弱引用,VALUE为软引用,就是这个意思。满足你说的那种功能。
那样的话,确实不错呢,有代码吗?学习学习。
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
请原谅我的愚钝,这样一行声明不知道想要表达什么意思?
呵呵,可能是我说得不名不白。ReferenceKeyType.WEAK,ReferenceValueType.SOFT构造函数传了这2个枚举进去,KEY为弱引用,VALUE为软引用,就是这个意思。满足你说的那种功能。
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
请原谅我的愚钝,这样一行声明不知道想要表达什么意思?
是的,里面的部分实现确实是Doug Lea贡献的。
当然了,如果不是线程安全的,岂能叫ConcurrentMap。
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
Hashtable太老土啦,线程安全我都用ConcurrentHashMap。什么?现在流行MapMaker?

JDK 1.5引入的ConcurrentHashMap由于其精巧的设计,更高的并发性能,捕获了大家的心,在并发场景中出场率极高,但随着深入的使用,很快的就发现了其中的不足。例如在以Map作为Cache的典型场景中,我们都需要有元素过期的处理,WeakHashMap是这方面的高手,但其在并发方面有点菜(非线程安全),当我们想让这两位大将同时上场的时候,就只能抓耳搔腮了。
Google Collections中的MapMaker融合了Weak Reference,线程安全,高并发性能,异步超时清理,自定义构建元素等强大功能于一身。(注)
常阅读优秀源代码的童鞋都知道,一般叫Maker的对象都是Builder模式,而这个MapMaker就是来"Build"Map的,下面的代码展示了如何构建一个高并发性能,线程安全的WeakHashMap.
public void testWeakKeys() throws Exception { ConcurrentMap<Key, Value> map = new MapMaker() .weakKeys() // 指定Map保存的Key为WeakReference机制 .makeMap(); Key key = new Key(); map.put(key, new Value()); // 加入元素 key = null; // key变成了WeakReference System.gc();// 触发垃圾回收 TimeUnit.SECONDS.sleep(1L); assertTrue(map.isEmpty()); // map空了,因为WeakReference被回收 }
是不是够简单?他不仅支持WeakKeys,还支持WeakValues。
public void testWeakValues() throws Exception { ConcurrentMap<Key, Value> map = new MapMaker() .weakValues() // 指定Map保存的Value为WeakReference机制 .makeMap(); Key key = new Key(); Value value = new Value(); map.put(key, value); // 加入元素 key = null; // Key成了WeakReference System.gc();// 触发垃圾回收 TimeUnit.SECONDS.sleep(1L); assertFalse(map.isEmpty()); // map里的东西还在,因为Value还是StrongReference value = null; // 这次value也变成了WeakReference System.gc(); // 触发垃圾回收 TimeUnit.SECONDS.sleep(1L); assertTrue(map.isEmpty()); // map真空了,因为Value是WeakReference被回收 }
还可以选用SoftKeys,和SoftValues,随意组合,比只能WeakKey的WeakHashMap扩展性强太多了。
再来看看On-demand value computation,自定义构建元素。想象下面的场景,你要为一个查询学生信息的DAO增加结果缓存,并且结果超过60秒过期,我们可以用装饰模式结合MapMaker简单的实现。
interface StudentDao { Information query(String name); } class StudentDaoImpl implements StudentDao { // 真正去查数据库的实现类 代码省略 } // 装饰器 class CachedStudentDao implements StudentDao { private final StudentDao studentDao; private final ConcurrentMap<String, Information> cache; public CachedStudentDao(final StudentDao studentDao) { Preconditions.checkNotNull(studentDao, "studentDao"); this.studentDao = studentDao; this.cache = new MapMaker() // 构建一个 computingMap .expiration(60, TimeUnit.SECONDS) // 元素60秒过期 .makeComputingMap(new Function<String, Information>(){ @Override public Information apply(String name) { return studentDao.query(name); } }); // 传入匿名Function自定义缓存的初始化。如果缓存中没有name对应的数据,则调用真正的dao去数据库查找数据,同时缓存结果。 } @Override public Information query(String name) { return cache.get(name); // 从computing cache中取结果 } } public void test() { StudentDao cachedStudentDao = new CachedStudentDao(studentDaoImpl); // 装饰了studenDaoImpl的cachedStudentDao具备了缓存结果的能力。 }
线程安全,高并发性能,元素过期都实现了,并且代码很简洁。多亏了MapMaker,脏活、累活,就交给它啦。不过要注意的是,要遵循ConcurrentHashMap的规范,其不允许有Null的Key和Value。如果查询出来的结果可能为Null的,可用简单的包装类包装一下,这里不给出代码了。
怎么样?你是不是心动了呢?快下载来看看吧。
注:参考该文章了解是什么WeakReference?http://www.iteye.com/topic/401478
评论
21 楼
Agrael
2010-05-21
Feiing 写道
Agrael 写道
private static final transient Map<Class<?>, CacheBeanInfo> CACHE_BEANINFO = new ReferenceMap<Class<?>, CacheBeanInfo>(ReferenceKeyType.WEAK,ReferenceValueType.SOFT);
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
没仔细看你的代码, 但请允许我凭臆断说几句大言不惭的话
1. 我不认为你的实现会比 google-collections 优秀, 因为 :
2. 我不认为你的水平会比 Bob Lee 或者 Doug Lea 高
所以
3. 我会在项目里用公认的优秀类库而不会因为自己开心就写一些帮助不大的东西
因为
4. 这会导致项目的维护成本增加
如果我想让别人认可我的作品
5. 如果允许, 我会把它开源让所有的人来试用, 我会写一个 feature list comparison 来比较它跟其他作品, 代码放在那, 孰优孰劣大家心里都会很明白
另外 , 个人认为用中文写注释是一个非常坏的习惯

我并没说和什么相比,我只是说自己多留意一下多用心,很多东西并不是不可能。
我也没和google-collections比,当然我的水平没有 Bob Lee 或者 Doug Lea 高,但是,请先看明白我想说的是什么:)
20 楼
Feiing
2010-05-21
Agrael 写道
private static final transient Map<Class<?>, CacheBeanInfo> CACHE_BEANINFO = new ReferenceMap<Class<?>, CacheBeanInfo>(ReferenceKeyType.WEAK,ReferenceValueType.SOFT);
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
没仔细看你的代码, 但请允许我凭臆断说几句大言不惭的话
1. 我不认为你的实现会比 google-collections 优秀, 因为 :
2. 我不认为你的水平会比 Bob Lee 或者 Doug Lea 高
所以
3. 我会在项目里用公认的优秀类库而不会因为自己开心就写一些帮助不大的东西
因为
4. 这会导致项目的维护成本增加
如果我想让别人认可我的作品
5. 如果允许, 我会把它开源让所有的人来试用, 我会写一个 feature list comparison 来比较它跟其他作品, 代码放在那, 孰优孰劣大家心里都会很明白
另外 , 个人认为用中文写注释是一个非常坏的习惯

19 楼
Agrael
2010-05-21
JavaYwsEye 写道
org.apache.commons.collections.map.ReferenceMap.java
此类在 commons-collections-3.2.1.jar
不知楼主有没有看过此类,并 和你自己所写有什么区别?
此类在 commons-collections-3.2.1.jar
不知楼主有没有看过此类,并 和你自己所写有什么区别?
我想你是问的我,不是楼主。
上面我就说了,不过我不知道你说的这个类,我看的是Xwork里的一个类,在我new一个实例就创建一个线程困扰的时候,看到那个类后把new一个实例就创建一个线程改为了只会有一个线程,除此之外,这个ReferenceMap已经和我发的代码差不多了。如果有相似的,我估计是思想大同小异吧。
18 楼
JavaYwsEye
2010-05-21
org.apache.commons.collections.map.ReferenceMap.java
此类在 commons-collections-3.2.1.jar
不知楼主有没有看过此类,并 和你自己所写有什么区别?
此类在 commons-collections-3.2.1.jar
不知楼主有没有看过此类,并 和你自己所写有什么区别?
17 楼
Agrael
2010-05-21
Norther 写道
Agrael 写道
Norther 写道
回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。
呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。
这个ReferenceMap我修改过无数次,最终形成了现在的版本。
在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。
至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。
你国外的朋友不会是Bob Lee吧?强的!
http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/base/FinalizablePhantomReference.java
绝对不是,而且当时我参考的也不是这个包的东西。

16 楼
Norther
2010-05-21
Agrael 写道
Norther 写道
回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。
呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。
这个ReferenceMap我修改过无数次,最终形成了现在的版本。
在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。
至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。
你国外的朋友不会是Bob Lee吧?强的!
http://code.google.com/p/google-collections/source/browse/trunk/src/com/google/common/base/FinalizablePhantomReference.java
15 楼
Agrael
2010-05-21
就之前我一直被WeakHashMap的并发问题困扰,在可能2年前吧,就准备封装ConcurrentHashMap来满足需求,但是当时到处找都没找到自己需要的,所以才自己写了个,经过很多次修改,最终才比较满意。后来发现XWORK里的时,已经和现在的代码区别不大了。至于为什么不实现ConcurrentMap。这个的话我觉得都到这一步了,如果哪天需要在ReferenceMap中单独出现这些方法的话,再改也没什么,毕竟现在我还有个CollectionUtils配合这个使用,呵呵。
14 楼
Agrael
2010-05-21
Norther 写道
回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,还差一截。
呵呵,你所包名改改这个我觉得我没这样做,如果我改包名的话,也是cn.agrael.原包名。
这个ReferenceMap我修改过无数次,最终形成了现在的版本。
在这个版本之前,我发现了XWORK里也有类似的东西,而且比我写得更好,所以我就参考着修改了下,修改的仅仅是从之前的每次创建一个ReferenceMap都有一个线程清理变到无论创建多少个ReferenceMap都只有一个线程清理。
至于FinalizableReference命名这个,我想说的是,这个名字还不是我自己命的,是我国外一个朋友帮我命的,我英语不好,所以叫他帮忙取的。呵呵。
13 楼
Norther
2010-05-21
回Agrael:
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,呵呵呵。
你研究精神值得我们学习,帖的代码看了一些,参考了很多现成的代码,连Magic Number都复制过来了,而且FinalizableReference这些的类,很眼熟,不知道你为什么不用现成的,要把人家的包名改改复制到自己的项目里用,并且你这个Map还有提高的空间,既然是ConcurrentMap就应该实现ConcurrentMap接口,否则putIfAbsent这种方法都没有,用起来也不方便,替代WeakHashMap或许可以,但是和拥有ComputingMap的MapMaker比,呵呵呵。
12 楼
JavaChaos
2010-05-21
从来没用过。学习一下。多谢LZ
11 楼
Agrael
2010-05-21
我已经发了一篇名叫《封装ConcurrentHashMap使其成为具有各种引用类型key与value的ReferenceMap》的帖子,那个是完整的介绍。
10 楼
Agrael
2010-05-21
恩,没问题的。一会我单独开个帖子,发个完整的。
package cn.agrael.collection; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.ref.Reference; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import cn.agrael.ref.FinalizablePhantomReference; import cn.agrael.ref.FinalizableReference; import cn.agrael.ref.FinalizableSoftReference; import cn.agrael.ref.FinalizableWeakReference; import cn.agrael.util.Assert; /** * 支持各种引用类型的 Map。 * <p> * 引用类型请参考 {@link java.lang.ref}与 {@link cn.agrael.ref} 的描述。 * </p> * <p> * 该 Map 的特性和 {@link ConcurrentHashMap} 一样。在第一次调用 put/putAll * 方法时(仅仅是在同一个类加载器中的第一次 * ,如果为同一类加载器,那么在put/putAll后,新创建的实例的put/putAll也不算做第一次),会有一个后台线程随之创建并启动 * ,该后台线程主要作用和垃圾回收交互,进行回收对象的清理。在清理 键 * 的同时,会一同清理掉 键的引用包装器 以及 值 和 值的引用包装器 以及 印射 ,在清理 值 时 ,会一同清理掉 值的引用包装器,然后从 Map 中移除印射到自身的 键 以及 印射 。 * </p> * <p> * 该清理是 异步 且 “即时” 的,会在垃圾回收的同时清理,不需要在下次对该 Map 操作时才清理包装引用的实例。 * </p> * * @author <a href="http://www.agrael.cn">李翔</a> * * @param <K> * 此映射维护的键类型 * @param <V> * 映射值的类型 */ public class ReferenceMap<K, V> extends AbstractMap<K, V> implements Map<K, V> { /** 版本号 */ private static final long serialVersionUID = -6254917146703219097L; private final ReferenceKeyType keyReferenceType; private final ReferenceValueType valueReferenceType; private transient int initialCapacity = 16; private transient float loadFactor = 0.75f; private transient int concurrencyLevel = 16; private transient ConcurrentMap<Object, Object> map; /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有默认初始容量、加载因子和 concurrencyLevel 的新的空映射。 * @param keyReferenceType key引用类型 。 * @param valueReferenceType value引用类型。 */ public ReferenceMap(ReferenceKeyType keyReferenceType ,ReferenceValueType valueReferenceType) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; map = new ConcurrentHashMap<Object, Object>(initialCapacity,loadFactor,concurrencyLevel); } /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有指定初始容量、默认加载因子和 concurrencyLevel 的新的空映射。 * @param keyReferenceType key引用类型。 * @param valueReferenceType value引用类型。 * @param initialCapacity 初始容量。该实现执行内部大小调整,以容纳这些元素。 */ public ReferenceMap(ReferenceKeyType keyReferenceType ,ReferenceValueType valueReferenceType, int initialCapacity) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; this.initialCapacity = initialCapacity; map = new ConcurrentHashMap<Object, Object>(initialCapacity,loadFactor,concurrencyLevel); } /** * 通过指定的 key引用类型 和 value引用类型 创建一个带有指定初始容量、加载因子和并发级别的新的空映射。 * @param keyReferenceType key引用类型。 * @param valueReferenceType value引用类型。 * @param initialCapacity 初始容量。该实现执行内部大小调整,以容纳这些元素。 * @param loadFactor 加载因子阈值,用来控制重新调整大小。在每 bin 中的平均元素数大于此阈值时,可能要重新调整大小。 * @param concurrencyLevel 当前更新线程的估计数。该实现将执行内部大小调整,以尽量容纳这些线程。 */ public ReferenceMap(ReferenceKeyType keyReferenceType ,ReferenceValueType valueReferenceType, int initialCapacity, float loadFactor, int concurrencyLevel) { this.keyReferenceType = keyReferenceType; this.valueReferenceType = valueReferenceType; this.concurrencyLevel = concurrencyLevel; this.initialCapacity = initialCapacity; this.loadFactor = loadFactor; map = new ConcurrentHashMap<Object, Object>(initialCapacity, loadFactor, concurrencyLevel); } @SuppressWarnings("unchecked") @Override public Set<K> keySet() { if(keyReferenceType == ReferenceKeyType.STRONG){ // 如果为强引用,则 map 中的 keySet 就是需要的 return (Set<K>) map.keySet(); } // 为其他引用 return new AbstractSet<K>() { public Iterator<K> iterator() { return new Iterator<K>() { private Iterator<Object> iterator = map.keySet().iterator(); public boolean hasNext() { return iterator.hasNext(); } public K next() { return getKey(iterator.next()); } public void remove() { iterator.remove(); } }; } public int size() { return map.size(); } }; } @Override public void clear() { map.clear(); } @Override public V remove(Object key) { Assert.notNull(key); Object keyReference = createKeyReferenceWrapper(key); Object returnValueReference = map.remove(keyReference); return getValue(returnValueReference); } @Override public boolean containsKey(Object key) { return map.containsKey(key); } @Override public int size() { return map.size(); } @Override public boolean isEmpty() { return map.isEmpty(); } @Override public V put(K key, V value) { Assert.notNull(key); Assert.notNull(value); Object keyReference = null; switch (keyReferenceType) { case STRONG: keyReference = key; break; case SOFT: keyReference = new FinalizableKeySoftReference<K>(key); break; case WEAK: keyReference = new FinalizableKeyWeakReference<K>(key); break; case PHANTOM: keyReference = new FinalizableKeyPhantomReference<K>(key); break; } Object valueReference = null; switch (valueReferenceType) { case STRONG: valueReference = value; break; case SOFT: valueReference = new FinalizableValueSoftReference<V>(keyReference ,value); break; case WEAK: valueReference = new FinalizableValueWeakReference<V>(keyReference ,value); break; case PHANTOM: valueReference = new FinalizableValuePhantomReference<V>(keyReference ,value); break; } Object returnValueReference = map.put(keyReference, valueReference); if(returnValueReference == null){ return null; } return getValue(returnValueReference); } @SuppressWarnings("unchecked") private V getValue(Object valueReference){ return (V) (valueReferenceType == ReferenceValueType.STRONG ? valueReference : valueReference == null ? null : ((Reference<V>) valueReference).get()); } @SuppressWarnings("unchecked") private K getKey(Object keyReference){ return (K) (keyReferenceType == ReferenceKeyType.STRONG ? keyReference : keyReference == null ? null : ((Reference<K>) keyReference).get()); } /** * 创建 Key 的印射包装器。 * @param key 要创建印射包装器的 key。 * @return 如果是强引用,返回 key 本身,否则返回 Key 的印射包装器。 */ private Object createKeyReferenceWrapper(Object key){ return keyReferenceType == ReferenceKeyType.STRONG ? key : new KeyReferenceWrapper(key); } /** * 得到 key 在内存中的地址的 hashCode。 * @param key 要得到在内存中的地址的 hashCode 的 key。 * @return key 在内存中的地址的 hashCode。 * @see System#identityHashCode(Object) */ private int keyHashCode(Object key){ return System.identityHashCode(key); } private boolean referenceEquals(Reference<?> reference , Object object){ if(reference == object){ // 直接引用相同 return true; } if(reference == null){ // 一方为 null 则返回 false(因为上个判断结合这个判断,object 一定不为 null) return false; } if(object instanceof Reference<?>){ // object 为引用类型,则比较引用类型中的值的引用 Object referenceValue = ((Reference<?>) object).get(); return referenceValue != null && reference.get() == referenceValue; } if(object instanceof KeyReferenceWrapper){ // object为 key 引用包装类型 return ((KeyReferenceWrapper) object).getReference() == reference.get(); } return false; } @Override public V get(Object key) { Assert.notNull(key); Object keyReference = createKeyReferenceWrapper(key); Object returnValueReference = map.get(keyReference); return getValue(returnValueReference); } public Set<Entry<K, V>> entrySet() { return new AbstractSet<Entry<K, V>>() { public Iterator<Entry<K, V>> iterator() { return new Iterator<Entry<K, V>>() { private Iterator<Entry<Object, Object>> iterator = map.entrySet().iterator(); public boolean hasNext() { return iterator.hasNext(); } public Entry<K, V> next() { final Entry<Object, Object> entry = iterator.next(); return new Entry<K, V>() { public K getKey() { return ReferenceMap.this.getKey(entry.getKey()); } public V getValue() { return ReferenceMap.this.getValue(entry.getValue()); } public V setValue(V value) { throw new UnsupportedOperationException("不支持的操作。"); } }; } public void remove() { iterator.remove(); } }; } public int size() { return map.size(); } }; } /** * 弱引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeyWeakReference<T> extends FinalizableWeakReference<T> implements FinalizableReference<T>{ private final int hashCode; /** * 构造一个新的 弱引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeyWeakReference(T referent) { super(referent); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { map.remove(this); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 弱引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValueWeakReference<T> extends FinalizableWeakReference<T> implements FinalizableReference<T>{ private Object keyReference; /** * 构造一个新的 弱引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValueWeakReference(Object keyReference ,T referent) { super(referent); this.keyReference = keyReference; } public void finalizeReferent() { map.remove(keyReference,this); } } /** * 软引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeySoftReference<T> extends FinalizableSoftReference<T> implements FinalizableReference<T>{ private final int hashCode; /** * 构造一个新的 软引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeySoftReference(T referent) { super(referent); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { map.remove(this); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 软引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValueSoftReference<T> extends FinalizableSoftReference<T> implements FinalizableReference<T>{ private Object keyReference; /** * 构造一个新的 软引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValueSoftReference(Object keyReference ,T referent) { super(referent); this.keyReference = keyReference; } public void finalizeReferent() { map.remove(keyReference,this); } } /** * 虚引用对象的键类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableKeyPhantomReference<T> extends FinalizablePhantomReference<T> implements FinalizableReference<T>{ private final int hashCode; /** * 构造一个新的 虚引用对象的键类 实例。 * @param referent 键。 */ protected FinalizableKeyPhantomReference(T referent) { super(referent); this.hashCode = keyHashCode(referent); } public void finalizeReferent() { map.remove(this); } @Override public int hashCode() { return hashCode; } @Override public boolean equals(Object object) { return referenceEquals(this, object); } } /** * 虚引用对象的值类。 * @author <a href="http://www.agrael.cn">李翔</a> * * @param <T> 引用类型 */ protected class FinalizableValuePhantomReference<T> extends FinalizablePhantomReference<T> implements FinalizableReference<T>{ private Object keyReference; /** * 构造一个新的 虚引用对象的值类 实例。 * @param keyReference 与此值关联的 键 。 * @param referent 值。 */ protected FinalizableValuePhantomReference(Object keyReference ,T referent) { super(referent); this.keyReference = keyReference; } public void finalizeReferent() { map.remove(keyReference,this); } } /** * 引用类型中的对象的另一个包装器,该包装器实现为引用类型中的对象保持 put 与 get 时用到的 hashCode 和 equals 方法的一致性。 * @author <a href="http://www.agrael.cn">李翔</a> * */ protected static class ReferenceWrapper{ protected final Object reference; /** * 使用一个引用类型中的对象实例构造一个新的包装器。 * @param reference 要包装的引用类型中的对象实例。 */ protected ReferenceWrapper(Object reference) { this.reference = reference; } /** * 得到被包装的对象。 * @return 被包装的对象。 */ protected Object getReference() { return reference; } /** * 调用包装对象的 hashCode 方法。 * @return 包装对象的 hashCode。 */ @Override public int hashCode() { return reference.hashCode(); } /** * 调用包装对象的 equals 方法比较。 * @param obj 要与之比较的对象。 * @return 如果传入的对象和包装对象“相等”则返回 true,否则返回 false。 */ @Override public boolean equals(Object obj) { // 使用包装对象的 equals return reference.equals(obj); } } /** * 专用于 key 的引用类型中的对象的另一个包装器。该包装器重写了 hashCode 方法,使用 {@link System#identityHashCode(Object)} 取得 hash值 。 * @author <a href="http://www.agrael.cn">李翔</a> * */ protected static class KeyReferenceWrapper extends ReferenceWrapper { /** * 使用一个引用类型中的 key对象实例 构造一个新的包装器。 * @param reference 要包装的引用类型中的key对象实例。 */ protected KeyReferenceWrapper(Object reference) { super(reference); } /** * 返回包装的 Key 的内存里的 hashCode。 * @return 包装的 Key 的内存里的 hashCode。 * @see System#identityHashCode(Object) */ @Override public int hashCode() { // 这里要认为同一内存地址的才是相同对象,所以取得内存地址中的 HASH码 return System.identityHashCode(reference); } } /** * 用作 K 的引用类型。 * @author <a href="http://www.agrael.cn">李翔</a> * */ public static enum ReferenceKeyType { /** 强引用 */ STRONG(Object.class), /** 软引用 */ SOFT(ReferenceMap.FinalizableKeySoftReference.class), /** 弱引用 */ WEAK(ReferenceMap.FinalizableKeyWeakReference.class), /** 虚引用 */ PHANTOM(ReferenceMap.FinalizableKeyPhantomReference.class); private final Class<?> referenceTypeClass; private ReferenceKeyType(Class<?> referenceTypeClass) { this.referenceTypeClass = referenceTypeClass; } Class<?> getReferenceTypeClass(){ return referenceTypeClass; } } /** * 用作 V 的引用类型。 * @author <a href="http://www.agrael.cn">李翔</a> * */ public static enum ReferenceValueType { /** 强引用 */ STRONG(Object.class), /** 软引用 */ SOFT(ReferenceMap.FinalizableValueSoftReference.class), /** 弱引用 */ WEAK(ReferenceMap.FinalizableValueWeakReference.class), /** 虚引用 */ PHANTOM(ReferenceMap.FinalizableValuePhantomReference.class); private final Class<?> referenceTypeClass; private ReferenceValueType(Class<?> referenceTypeClass) { this.referenceTypeClass = referenceTypeClass; } Class<?> getReferenceTypeClass(){ return referenceTypeClass; } } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeInt(size()); out.writeFloat(loadFactor); out.writeInt(concurrencyLevel); for (Map.Entry<Object, Object> entry : map.entrySet()) { Object key = getKey(entry.getKey()); Object value = getValue(entry.getValue()); if (key != null && value != null) { out.writeObject(key); out.writeObject(value); } } out.writeObject(null); } @SuppressWarnings("unchecked") private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); int size = in.readInt(); float loadFactor = in.readFloat(); int concurrencyLevel = in.readInt(); this.initialCapacity = size; this.map = new ConcurrentHashMap<Object, Object>(size,loadFactor,concurrencyLevel); while (true) { K key = (K) in.readObject(); if (key == null) { break; } V value = (V) in.readObject(); put(key, value); } } }
9 楼
Norther
2010-05-21
Agrael 写道
Norther 写道
Agrael 写道
private static final transient Map<Class<?>, CacheBeanInfo> CACHE_BEANINFO = new ReferenceMap<Class<?>, CacheBeanInfo>(ReferenceKeyType.WEAK,ReferenceValueType.SOFT);
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
请原谅我的愚钝,这样一行声明不知道想要表达什么意思?
呵呵,可能是我说得不名不白。ReferenceKeyType.WEAK,ReferenceValueType.SOFT构造函数传了这2个枚举进去,KEY为弱引用,VALUE为软引用,就是这个意思。满足你说的那种功能。
那样的话,确实不错呢,有代码吗?学习学习。
8 楼
Agrael
2010-05-21
Norther 写道
Agrael 写道
private static final transient Map<Class<?>, CacheBeanInfo> CACHE_BEANINFO = new ReferenceMap<Class<?>, CacheBeanInfo>(ReferenceKeyType.WEAK,ReferenceValueType.SOFT);
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
请原谅我的愚钝,这样一行声明不知道想要表达什么意思?
呵呵,可能是我说得不名不白。ReferenceKeyType.WEAK,ReferenceValueType.SOFT构造函数传了这2个枚举进去,KEY为弱引用,VALUE为软引用,就是这个意思。满足你说的那种功能。
7 楼
Norther
2010-05-21
Agrael 写道
private static final transient Map<Class<?>, CacheBeanInfo> CACHE_BEANINFO = new ReferenceMap<Class<?>, CacheBeanInfo>(ReferenceKeyType.WEAK,ReferenceValueType.SOFT);
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
请原谅我的愚钝,这样一行声明不知道想要表达什么意思?
6 楼
Norther
2010-05-21
beneo 写道
不会是 Doug Lea 跑到 google 又去弄了一个 concurrent package 吧
是的,里面的部分实现确实是Doug Lea贡献的。
5 楼
Norther
2010-05-21
JE帐号 写道
makeComputingMap 加匿名function那段.apply应该是线程安全的吧?
当然了,如果不是线程安全的,岂能叫ConcurrentMap。
4 楼
Agrael
2010-05-20
private static final transient Map<Class<?>, CacheBeanInfo> CACHE_BEANINFO = new ReferenceMap<Class<?>, CacheBeanInfo>(ReferenceKeyType.WEAK,ReferenceValueType.SOFT);
自己写的一个ReferenceMap,封装了ConcurrentHashMap。
其实有时候自己多留意一下多用心,很多东西并不是不可能。
在使用开源包的时候,还是要自己思考下如果是自己的话该如何实现。不然真成了只会找开源的人了。
3 楼
beneo
2010-05-20
不会是 Doug Lea 跑到 google 又去弄了一个 concurrent package 吧
2 楼
JE帐号
2010-05-20
makeComputingMap 加匿名function那段.apply应该是线程安全的吧?
相关推荐
Google Guava Collections 是 Java Collections Framework 的一个强大且实用的非官方扩展 API。它由 Google 工程师 Kevin Bourrillion 和 Jared Levy 在著名的“20%”时间开发而成,并得到了 Java Collections ...
### Google Guava Collections 使用介绍 #### 一、Google Guava Collections 概览 Google Guava Collections,简称Guava Collections,是对Java Collections Framework进行增强和扩展的开源项目。它由Google工程师...
Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, 等等. 这些高质量的 API 可以使你...
guava类似Apache Commons工具集包含了若干被Google的 Java项目广泛依赖 的核心库
总结来说,Guava-19.0的这两个jar文件以及对应的sources.jar,为Java开发者提供了强大的工具集,不仅可以在常规Java项目中使用,也能很好地适应GWT的开发需求。源码的提供使得学习和定制变得更加容易,是Java开发中...
通过阅读"Getting Started with Google Guava"、"JavaCachingwithGuava"、"Guava_for_Netflix_"和"guava-concurrent-slides"等文档,你可以深入理解Guava的各种特性和使用场景,从而在实际开发中更好地利用Guava提升...
Guava is a set of core Java libraries from Google that includes new collection types (such as multimap and multiset), immutable collections, a graph library, and utilities for concurrency, I/O, ...
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] ...
Google的Guava是Java开发中一个非常强大的工具库,它由Google工程师开发并维护,提供了一套丰富的Java实用工具集合。Guava的目的是为了简化Java编程,减少代码冗余和提升代码质量。Guava中包含的工具种类繁多,涵盖...
Google Guava是一个比较有趣的框架,它提供了很多有趣的的功能, google Guava 给开发者提供了如下常用功能: 集合(collections) 缓存(caching) 原生的类型支持(primitives support) 并发类库(concurrency ...
1. **集合框架增强**:Guava 提供了丰富的集合类,如 Multiset(多集合)、Multimap(多映射)、Immutable collections(不可变集合)等,这些集合在功能和性能上都优于 Java 标准库中的集合。 2. **缓存**:Guava ...
的情况,这正是Google Collections库提供的一个强大功能。 `Maps`是Google Collections中的一个关键模块,它提供了许多高级的映射操作,比如创建不可变映射、构建双向映射、过滤映射以及并行流处理等。下面我们将...
在版本 30.1.1 中,Guava 继续提供了一系列强大且实用的类,帮助开发者更高效地编写 Java 代码。本文将详细介绍其中的一些重要类,并通过实践代码来展示它们的用法。 1. **Immutable Collections** - `...
扩展组件包括guava-annotations、guava-base、guava-bootstrap、guava-collections、guava-concurrent、guava-gwt、guava-io、guava-parent、guava-primitives、listenablefuture、guava-testlib等。
Guava是Google开发的一个Java库,它包含许多Google核心库中的高级集合、缓存、原生类型支持、并发包、字符串处理、I/O等工具类。版本33.0.0是Guava的一个更新,提供了最新的功能改进和错误修复。在深入探讨Guava常用...
Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, caching, primitives support, concurrency libraries, common annotations, string processing, I/O, 等等. 这些高质量的 API 可以使你...
google-collections-1.0-rc2.jar 的jar包,放心使用。
Guava是Google为Java平台设计的一个开源库,它极大地扩展了Java的标准库,尤其是在集合、缓存、并发和I/O等方面。Guava的核心特性包括: 1. **集合框架增强**:Guava提供了丰富的集合类,如Multiset(多集)、...
Guava工程包含了若干被Google的 Java项目广泛依赖 的核心库,例如:集合 [collections] 、缓存 [caching] 、原生类型支持 [primitives support] 、并发库 [concurrency libraries] 、通用注解 [common annotations] ...
Write more robust code that is easier to read and maintain, Learn how to use Preconditions to prevent and find errors faster, Shows how Guava Collections can make working with Java Collections a ...