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. Java代码
收藏代码

public void testWeakKeys() throws Exception {
ConcurrentMap 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。 Java代码
收藏代码

public void testWeakValues() throws Exception {
ConcurrentMap 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简单的实现。 Java代码
收藏代码

interface StudentDao {
Information query(String name);
}

class StudentDaoImpl implements StudentDao {
// 真正去查数据库的实现类 代码省略
}
// 装饰器
class CachedStudentDao implements StudentDao {
private final StudentDao studentDao;
private final ConcurrentMap 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(){  
            @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的,可用简单的包装类包装一下,这里不给出代码了。 怎么样?你是不是心动了呢?快下载来看看吧。

你可能感兴趣的:(Google Collections(Guava)中强大的Concurrent MapMaker)