java中是否有线程安全且元素唯一的队列?

java中是否有线程安全且元素唯一的队列?,java,concurrenthashmap,Java,Concurrenthashmap,就像“ConcurrentHashMap”和“ConcurrentLinkedQueue”的混合体 以下是我的要求: 我需要一个异步更新的缓存系统。这意味着在将每个实体设置为memcache之前,我会将其包装。warpper中有一个时间戳,指示其内容何时到期。来自前端的每个请求都会从memcache获取数据,如果warpper显示过期,则会生成一个更新事件并将其放入concurrentLinkedQueue,然后等待异步更新。 问题是:我不想徒劳地多次更新实体。在向队列添加事件之前,我希望找到一

就像“ConcurrentHashMap”和“ConcurrentLinkedQueue”的混合体

以下是我的要求:
我需要一个异步更新的缓存系统。这意味着在将每个实体设置为memcache之前,我会将其包装。warpper中有一个时间戳,指示其内容何时到期。来自前端的每个请求都会从memcache获取数据,如果warpper显示过期,则会生成一个更新事件并将其放入concurrentLinkedQueue,然后等待异步更新。
问题是:我不想徒劳地多次更新实体。在向队列添加事件之前,我希望找到一种方法来确保队列中已经没有相同实体的事件

如果我这样做可以吗

1,创建一个warpper类,它包含一个hashMap和一个linkedList。其所有方法都是同步的:

public synchronized boolean add(String key,Object value){
    if(hashMap.containsKey(key)){
        return false;
    }else{
        hashMap.put(key,value);
        return linkedList.offer(value);
    }
}  

我相信这个解决方案会非常缓慢。
也许它就像Collections.synchronizedMap(newLinkedHashMap())一样

2,只需使用concurrentHashMap。如果我需要“poll”操作,请迭代其中的一个元素

public Object poll(){
    Collection valueColl = concurrentHashMap.values();
    if(valueColl.isEmpty()){
        retrun null;
    }
    return valueColl.get(0);
}  
动作
concurrentHashMap.values().get(0)
是否缓慢

3、查看“ConcurrentHashMap”和“ConcurrentLinkedQueue”的源代码,如果可能,编写一个“ConcurrentUniqueLinkedQueue”。
目前看来这对我来说有点难


那么,你们怎么说呢?

我想你们不想放弃最新的更新。也许你让事情变得比需要的更复杂了

public void add(K key, V value) {
    concurrentMap.put(key, value);
    queue.add(key);
}

public V poll() {
    for(K key; (key = queue.take()) != null;) {
        V value = concurrentMap.remove(key);
        if (value != null)
           return value;
        // value will be null if it's a duplicate so ignore and look for more.
    }
    return null;
}
这将按队列顺序为您提供密钥的最新值。它不需要任何锁定。

import java.util.LinkedHashSet;
import java.util.LinkedHashSet;
import java.util.Queue;
import java.util.concurrent.locks.ReentrantLock;

public class ConcurrentSetQueue<E> extends LinkedHashSet<E> implements Queue<E> {

    /**
     * 
     */
    private static final long serialVersionUID = 7906542722835397462L;

    final java.util.concurrent.locks.ReentrantLock lock = new ReentrantLock();

    public E remove() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E next = iterator().next();
            remove(next);
            return next;
        } finally {
            lock.unlock();
        }
    }

    @Override
    public E element() {
        return iterator().next();
    }

    @Override
    public boolean offer(E arg0) {
        return add(arg0);
    }

    @Override
    public E peek() {
        return element();
    }

    @Override
    public E poll() {
        return remove();
    }

}
导入java.util.Queue; 导入java.util.concurrent.locks.ReentrantLock; 公共类ConcurrentSetQueue扩展LinkedHashSet实现队列{ /** * */ 私有静态最终长serialVersionUID=7906542722835397462L; final java.util.concurrent.locks.ReentrantLock lock=new ReentrantLock(); 公共E删除(){ 最终重入锁定=this.lock; lock.lock(); 试一试{ E next=迭代器().next(); 移除(下一个); 下一步返回; }最后{ lock.unlock(); } } @凌驾 公共E元素(){ 返回迭代器().next(); } @凌驾 公共布尔报价(E arg0){ 返回add(arg0); } @凌驾 公共E peek(){ 返回元素(); } @凌驾 公众电子投票{ 返回删除(); } }
“我相信这个解决方案会非常慢。”你试过了吗?在我看来,这不应该太糟糕。
add
方法中的所有操作都非常快。而且我认为这是一个非常干净的解决方案。但我会用hashSet替换hashMap,因为这里没有真正的hashMap。你检查过GuavaAPI吗@Nikita实际上HashSet在内部使用HashMap。更重要的是,我阅读了EHCache或Hazelcast文档。你可以找到你需要的东西。不要再发明轮子了。@PiotrGwiazda我是根据HashMap知道的。但为了清楚起见,我更喜欢这里的HashSet。@Nikita当然你是对的。如果你正在使用HashMap(或HashSet)检查事件是否已经存在,请不要忘记在put()之后删除它,否则很快就会出现内存泄漏。HashMap/Set将保持对对象的强引用,并且它们永远不会被GCed。好的,很好的解决方案,我认为它会起作用。多谢各位@PeterLawrey@watchzerg注意,我已经修好了。