锁定老帖子 主题:高速缓存实现
精华帖 (0) :: 良好帖 (0) :: 新手帖 (15) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-06-08
你addElement的原子性是基于putIfAbsent是原子的,所以你还是用了concurrentHashMap内部的锁了,没看出什么特别有价值的地方
|
|
返回顶楼 | |
发表时间:2010-06-08
tyzqqq 写道 getElement没必要加线程锁吧,它仅仅是取值
getElement()的确不需要锁! |
|
返回顶楼 | |
发表时间:2010-06-08
最后修改:2010-06-08
wkoffee说:"你addElement的原子性是基于putIfAbsent是原子的,所以你还是用了concurrentHashMap内部的锁了,没看出什么特别有价值的地方".
说明如下:这里主要是想说明即便此时出现了多线程的情况,当第二个线程来请求获得对应key的value时,只要发现已经有第一个线程在创建对应value后,只需要等待第一个线程的结果就行了,这也就是为什么要使用Futuretask的目的,这样就可以很好的避免在创建比较消耗性能的value对象的性能损失. |
|
返回顶楼 | |
发表时间:2010-06-09
最后修改:2010-06-09
kazy 写道 从另外的地方抄个例子过来,
ConcurrentHashMap<String,String> map; String getString(String name) { String x = map.get(name); if (x == null) { x = new String(); map.put(name, x); } return x; } 如果你只调用get(),或只调用put()时,ConcurrentHashMap是线程安全的。 但是,在你调用完get后,调用put之前, 如果有另外一个线程调用了map.put(name, x), 你再去执行map.put(name,x), 就很可能把前面的操作结果覆盖掉了。 所以,即使在线程安全的情况下, 你还是有可能违反原子操作的规则。 同意kazy的观点,在多个线程同时进入到null里的时候,eval 和future 可能会被创建很多个。 另外又看了一下putIfAbsent方法,大概意思是 if (!map.containsKey(key)) return map.put(key, value); else return map.get(key); 如果这样的话,楼主首先使用有锁的map将future放入,保证此时map的future唯一,如果返回值是null说明是该线程首次放入,然后future做生成真正value的操作,这样感觉应该是可以的。 不过这样的话,是否一次就可以搞定value的值,而不需要while(true)了? |
|
返回顶楼 | |
发表时间:2010-06-09
关键点是LZ的cache是不能修改的吧。一旦put进去,就不会改了,其他线程只能分享胜利成果了。
所以线程安全了。 |
|
返回顶楼 | |
发表时间:2010-06-09
kazy 写道 从另外的地方抄个例子过来,
ConcurrentHashMap<String,String> map; String getString(String name) { String x = map.get(name); if (x == null) { x = new String(); map.put(name, x); } return x; } 如果你只调用get(),或只调用put()时,ConcurrentHashMap是线程安全的。 但是,在你调用完get后,调用put之前, 如果有另外一个线程调用了map.put(name, x), 你再去执行map.put(name,x), 就很可能把前面的操作结果覆盖掉了。 所以,即使在线程安全的情况下, 你还是有可能违反原子操作的规则。 这个要顶。不知道LZ的需求会不会break这一条 |
|
返回顶楼 | |
发表时间:2010-06-09
archerfrank 写道 关键点是LZ的cache是不能修改的吧。一旦put进去,就不会改了,其他线程只能分享胜利成果了。
所以线程安全了。 当然这里没有考虑到cache的修改问题,在实际应用中cache的修改问题是和业务场景挂钩的,也就所说的缓存策略的问题。 |
|
返回顶楼 | |
发表时间:2010-06-09
hankesi2000 写道 kazy 写道 从另外的地方抄个例子过来,
ConcurrentHashMap<String,String> map; String getString(String name) { String x = map.get(name); if (x == null) { x = new String(); map.put(name, x); } return x; } 如果你只调用get(),或只调用put()时,ConcurrentHashMap是线程安全的。 但是,在你调用完get后,调用put之前, 如果有另外一个线程调用了map.put(name, x), 你再去执行map.put(name,x), 就很可能把前面的操作结果覆盖掉了。 所以,即使在线程安全的情况下, 你还是有可能违反原子操作的规则。 同意kazy的观点,在多个线程同时进入到null里的时候,eval 和future 可能会被创建很多个。 另外又看了一下putIfAbsent方法,大概意思是 if (!map.containsKey(key)) return map.put(key, value); else return map.get(key); 如果这样的话,楼主首先使用有锁的map将future放入,保证此时map的future唯一,如果返回值是null说明是该线程首次放入,然后future做生成真正value的操作,这样感觉应该是可以的。 不过这样的话,是否一次就可以搞定value的值,而不需要while(true)了? 因为在利用FutureTask生成Value的过程中,有可能出现异常,所以这里需要while(true)来做轮询,知道对应key有一个对应的FutureTask放入Map中。 |
|
返回顶楼 | |
发表时间:2010-06-09
kazy 写道 从另外的地方抄个例子过来,
ConcurrentHashMap<String,String> map; String getString(String name) { String x = map.get(name); if (x == null) { x = new String(); map.put(name, x); } return x; } 如果你只调用get(),或只调用put()时,ConcurrentHashMap是线程安全的。 但是,在你调用完get后,调用put之前, 如果有另外一个线程调用了map.put(name, x), 你再去执行map.put(name,x), 就很可能把前面的操作结果覆盖掉了。 所以,即使在线程安全的情况下, 你还是有可能违反原子操作的规则。 你提出的这个问题我个人觉得应该不会出现,因为在put前利用了putIfAbent来保证该key对应的FutureTask是第一次put到Map,如果不是第一次此时只需要等待已经put的FutureTask执行获得value的结果,然后分享胜利果实即可. |
|
返回顶楼 | |
发表时间:2010-06-09
soongbo 写道 kazy 写道 从另外的地方抄个例子过来,
ConcurrentHashMap<String,String> map; String getString(String name) { String x = map.get(name); if (x == null) { x = new String(); map.put(name, x); } return x; } 如果你只调用get(),或只调用put()时,ConcurrentHashMap是线程安全的。 但是,在你调用完get后,调用put之前, 如果有另外一个线程调用了map.put(name, x), 你再去执行map.put(name,x), 就很可能把前面的操作结果覆盖掉了。 所以,即使在线程安全的情况下, 你还是有可能违反原子操作的规则。 你提出的这个问题我个人觉得应该不会出现,因为在put前利用了putIfAbent来保证该key对应的FutureTask是第一次put到Map,如果不是第一次此时只需要等待已经put的FutureTask执行获得value的结果,然后分享胜利果实即可. 的确putIfAbent能够保证只有唯一一个key,不过可惜的是你在调用putIfAbent前,有可能多个线程一起计算同一个key的value 你觉得这个的开销大还是锁的开销大 |
|
返回顶楼 | |