当前位置: 代码迷 >> J2SE >> ConcurrentHashMap使用有关问题
  详细解决方案

ConcurrentHashMap使用有关问题

热度:148   发布时间:2016-04-23 20:43:21.0
ConcurrentHashMap使用问题
想用ConcurrentHashMap做一个简单的缓存,存储对象,假如有如下场景:
A  a = map.get(key);
if(a==null)
{
     a = new A();
     map.putIfAbsent(key,a);
}
else{
     a.setTimes(i++);
     map.put(key,a);
}


这样是否能保证对象a的判空,修改,以及map读写是线程安全的
如果A的构造不耗时,是否有必要处理为线程安全的写法

------解决方案--------------------
不能。
比如你判断了a!=null;正准备执行else的语句。很不巧另外一个线程对你的map进行的操作,导致你的a现在等于null
,之前的线程继续执行else语句,这个时候a=null就会抛出空指针异常

一般比较常用的方法是用synchronized关键字
------解决方案--------------------
这肯定不行了,虽然ConcurrentHashMap是线程安全的,但是像你这样写,就不是了,你应该用synchronized块,把那段判断语句包围起来!
------解决方案--------------------


private final static ConcurrentMap<String, Future<Object>> cached = new ConcurrentHashMap<String, Future<Object>>();

public Object get(String key) {
Future<Object> future = cached.get(key);
if (future == null) {
Future<Object> newFutrue = new FutureTask<Object>(
new Callable<Object>() {
@Override
public Object call() throws Exception {
Object object = null;
//TODO  真正的获取value
return object;
}
});
// put if absent 防止缓存穿透。防止同一个Key,多个线程没命中的情况下,穿透至缓存。
future = cached.putIfAbsent(key, newFutrue);
if (future == null) {
future = newFutrue;
}
((FutureTask<Object>) future).run();
}

Object value = null;
try {
value = future.get(30, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return value;
}



本地缓存,请用Future   解决两个问题,
1   不用同步  2  解决缓存穿透,防止同一个KEY 没命中之后,同时访问后端。
------解决方案--------------------
正确的用法是:
V v = map.get(k);
if (v == null) {
  V _v = new V();
  v = map.putIfAbsent(k, _v);
  if (v == null) {v = _v;}
}

这段代码可以在线程中执行,得到正确的 v。
  相关解决方案