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

时间:2022-12-22 21:04:06

Like a hybrid of "ConcurrentHashMap" and "ConcurrentLinkedQueue".

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

Here is my requirements:
I need a asynchronous updated cache system. That means I wrap every entity before set it into memcache. There is a timestamp in the warpper which indicate when its content should expire. Each request from front side would fetch data from memcache, and if the warpper shows expiration, an update event would be generated and put into a concurrentLinkedQueue, then waiting to be updated asynchronously.
The problem is: I don't want to update an entity more than once in vain. Before adding an event to the queue, I wish to find a way to make sure there is no event for the same entity in the queue already.

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

Is that OK if I do it in these ways?

如果我以这些方式这样做,那可以吗?

1,Create a warpper Class, it contains a hashMap and a linkedList in it. All its method is synchronized:

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);
    }
}  

I believe this solution would be extremely slow.
Maybe It's just like Collections.synchronizedMap(new LinkedHashMap()).

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

2,Just use a concurrentHashMap. If I need "poll" action, iterator an element from it.

2,只需使用concurrentHashMap即可。如果我需要“poll”动作,则从中迭代一个元素。

public Object poll(){
    Collection valueColl = concurrentHashMap.values();
    if(valueColl.isEmpty()){
        retrun null;
    }
    return valueColl.get(0);
}  

The action concurrentHashMap.values().get(0) is slow or not?

并发HashMap.values()。get(0)的动作是慢还是没有?

3,Looking into the source code of "ConcurrentHashMap" and "ConcurrentLinkedQueue", then write an "ConcurrentUniqueLinkedQueue" if possible.
This looks a little hard for me for the moment.

3,查看“ConcurrentHashMap”和“ConcurrentLinkedQueue”的源代码,如果可能的话写一个“ConcurrentUniqueLinkedQueue”。这对我来说现在看起来有点困难。

so, how would you guys say?

所以,你们怎么说?

2 个解决方案

#1


5  

I don't imagine you want to discard the latest updates. Perhaps you are making it more complicated than it needs to be.

我不认为你想丢弃最新的更新。也许你使它变得比它需要的更复杂。

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;
}

This will give you the latest value for key in queued order. It doesn't need any locking.

这将为您提供排队顺序中键的最新值。它不需要任何锁定。

#2


0  

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();
    }

}

#1


5  

I don't imagine you want to discard the latest updates. Perhaps you are making it more complicated than it needs to be.

我不认为你想丢弃最新的更新。也许你使它变得比它需要的更复杂。

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;
}

This will give you the latest value for key in queued order. It doesn't need any locking.

这将为您提供排队顺序中键的最新值。它不需要任何锁定。

#2


0  

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();
    }

}