Java 如何以原子方式插入和更新CHM中特定密钥的队列?
我正在使用Java7。在一个由多个线程填充的类中,我有一个Java 如何以原子方式插入和更新CHM中特定密钥的队列?,java,multithreading,thread-safety,Java,Multithreading,Thread Safety,我正在使用Java7。在一个由多个线程填充的类中,我有一个ConcurrentHashMap围绕AtomicReference,如下所示: private final AtomicReference<ConcurrentHashMap<Channel, ConcurrentLinkedQueue<Holder>>> channelByHolderReference = new AtomicReference<>(new Conc
ConcurrentHashMap
围绕AtomicReference
,如下所示:
private final AtomicReference<ConcurrentHashMap<Channel, ConcurrentLinkedQueue<Holder>>> channelByHolderReference =
new AtomicReference<>(new ConcurrentHashMap<Channel, ConcurrentLinkedQueue<Holder>>());
// below method will be called by multiple threads to populate and update the map
// is below method thread safe and I won't loose any update?
public void add(final Channel channel, final Holder holder) {
ConcurrentMap<Channel, ConcurrentLinkedQueue<Holder>> holderByChannel =
channelByHolderReference.get();
ConcurrentLinkedQueue<Holder> messageHolder = holderByChannel.get(channel);
if (messageHolder == null) {
messageHolder = Queues.newConcurrentLinkedQueue();
ConcurrentLinkedQueue<Holder> currentMessageHolder =
holderByChannel.putIfAbsent(channel, messageHolder);
if (currentMessageHolder != null)
messageHolder = currentMessageHolder;
}
messageHolder.add(holder);
}
// called only by single background thread every 30 seconds
public void send() {
ConcurrentHashMap<Channel, ConcurrentLinkedQueue<Holder>> holderByChannel =
channelByHolderReference
.getAndSet(new ConcurrentHashMap<Channel, ConcurrentLinkedQueue<Holder>>());
for (Entry<Channel, ConcurrentLinkedQueue<Holder>> entry : holderByChannel
.entrySet()) {
// now iterate the map and do some processing
}
}
私有最终原子引用channelByHolderReference=
新的原子引用(新的ConcurrentHashMap());
//多个线程将调用下面的方法来填充和更新映射
//下面的方法是线程安全的,我不会丢失任何更新吗?
公共无效添加(最终通道,最终持有人){
ConcurrentMap holderByChannel=
channelByHolderReference.get();
ConcurrentLinkedQueue messageHolder=holderByChannel.get(通道);
if(messageHolder==null){
messageHolder=Queues.newConcurrentLinkedQueue();
ConcurrentLinkedQueue currentMessageHolder=
holderByChannel.putIfAbsent(通道,消息持有者);
if(currentMessageHolder!=null)
messageHolder=currentMessageHolder;
}
messageHolder.add(holder);
}
//每30秒仅由单个后台线程调用
公共无效发送(){
ConcurrentHashMapHolderByChannel=
channelByHolderReference
.getAndSet(新的ConcurrentHashMap());
对于(条目:holderByChannel
.entrySet()){
//现在迭代映射并进行一些处理
}
}
对于每个频道
我将有多个持有者
对象,这就是为什么每个频道都有持有者
对象的队列
。这里的Channel
是我代码中的一个枚举
我上面的add
方法将由多个线程调用,然后我在同一个类中有另一个send
方法,该方法仅由单个后台线程每隔几秒钟调用一次。因此,无论我在该映射中有什么,我都会从一个后台线程每隔30秒发送一次(通过调用send方法)
我的问题是-我的
add
方法在填充和更新每个通道的多个holder
对象的映射时是否线程安全?我是否需要AtomicReference
,因为据我所知,CHM已经同步了,所以我可能不需要它?请查看使用该设计可能会丢失消息。@Holger在代码的哪一部分,我会丢失消息?你能解释一下吗?我做错什么了吗?我认为这是Java7中的双重检查锁定方法,因为我现在无法使用computeiFabSend
。在send()
中,您正在用新映射替换映射。此时,可能有一个线程(甚至多个线程)仍在使用add
中的旧映射,并且无法保证send()
中的循环运行得足够慢,无法查看所有这些更新。当send()
退出时,可能仍然有线程没有在旧映射上完成add
操作。hmmm我明白你的意思了。。所以,我应该在getAndSet
行之后睡一段时间(我知道这不是一个好主意),还是有更好的方法不丢失任何数据?