Stu*_*son 22 java multithreading concurrenthashmap
是否保证通过不同的线程看到以前的?我的期望是,并且阅读JavaDocs似乎表明了这一点,但我99%确信现实是不同的.在我的生产服务器上,下面似乎正在发生.(我已经记录了它.)ConcurrentHashMap.get()
ConcurrentHashMap.put()
伪代码示例:
static final ConcurrentHashMap map = new ConcurrentHashMap();
//sharedLock is key specific. One map, many keys. There is a 1:1
// relationship between key and Foo instance.
void doSomething(Semaphore sharedLock) {
boolean haveLock = sharedLock.tryAcquire(3000, MILLISECONDS);
if (haveLock) {
log("Have lock: " + threadId);
Foo foo = map.get("key");
log("foo=" + foo);
if (foo == null) {
log("New foo time! " + threadId);
foo = new Foo(); //foo is expensive to instance
map.put("key", foo);
} else
log("Found foo:" + threadId);
log("foo=" + foo);
sharedLock.release();
} else
log("No lock acquired");
}
Run Code Online (Sandbox Code Playgroud)
似乎正在发生的事情是这样的:
Thread 1 Thread 2
- request lock - request lock
- have lock - blocked waiting for lock
- get from map, nothing there
- create new foo
- place new foo in map
- logs foo.toString()
- release lock
- exit method - have lock
- get from map, NOTHING THERE!!! (Why not?)
- create new foo
- place new foo in map
- logs foo.toString()
- release lock
- exit method
Run Code Online (Sandbox Code Playgroud)
所以,我的输出看起来像这样:
Have lock: 1
foo=null
New foo time! 1
foo=foo@cafebabe420
Have lock: 2
foo=null
New foo time! 2
foo=foo@boof00boo
Run Code Online (Sandbox Code Playgroud)
第二个线程没有立即看到放!为什么?在我的生产系统上,有更多的线程,我只看到一个线程,第一个紧跟在线程1之后,有一个问题.
我甚至尝试将ConcurrentHashMap上的并发级别缩减到1,而不是它应该重要.例如:
static ConcurrentHashMap map = new ConcurrentHashMap(32, 1);
Run Code Online (Sandbox Code Playgroud)
我哪里错了?我的期望?或者我的代码(真正的软件,而不是上面的代码)中有一些错误导致了这个问题吗?我反复思考过,99%肯定我正确处理锁定.我甚至无法理解ConcurrentHashMap
JVM中的错误. 请救我自己.
可能相关的Gorey细节:
Linux mysvr 2.6.9-78.0.5.ELsmp #1 SMP
... x86_64 GNU/Linux
)build 1.6.0_07-b06
,64-Bit Server VM (build 10.0-b23, mixed mode)
)Dav*_*sel 10
基于在高速缓存中找不到它而在高速缓存中创建昂贵的创建对象的问题是已知问题.幸运的是,这已经实施了.
您可以使用地图制作工具从谷歌Collecitons.您只需给它一个回调来创建您的对象,如果客户端代码在地图中查找并且映射为空,则调用回调并将结果放入映射中.
见MapMaker javadocs ......
ConcurrentMap<Key, Graph> graphs = new MapMaker()
.concurrencyLevel(32)
.softKeys()
.weakValues()
.expiration(30, TimeUnit.MINUTES)
.makeComputingMap(
new Function<Key, Graph>() {
public Graph apply(Key key) {
return createExpensiveGraph(key);
}
});
Run Code Online (Sandbox Code Playgroud)
顺便说一句,在您的原始示例中,使用ConcurrentHashMap没有任何优势,因为您锁定了每个访问,为什么不在锁定的部分中使用普通的HashMap?
这里有一些好的答案,但据我所知,没有人实际上提出了一个问题的规范答案:"ConcurrentHashMap.get()保证通过不同的线程看到以前的ConcurrentHashMap.put()".那些说"是"的人没有提供消息来源.
所以:是的,它是有保证的.来源(请参阅"内存一致性属性"一节):
在将对象放入任何并发集合之前的线程中的操作发生在从另一个线程中的集合访问或移除该元素之后的操作之前.
归档时间: |
|
查看次数: |
13713 次 |
最近记录: |