支持优先队列操作的TreeSet

来源:互联网 发布:昆仑虚麒麟臂升阶数据 编辑:程序博客网 时间:2024/06/10 16:13

目的

由于项目需求,需要一个去重的优先级队列,参考了一些资料,jdk没有找到合适的结构,考虑重写一个。

思路

大体实现的思路有2个
1.维护一个优先级队列和HashSet,元素入队列出队列时同步到HashSet,且入队列时确保HashSet不包含当前元素,否则直接返回成功而不入队列
个人觉得同步两个容器的状态不够elegant

2.参考PriorityBlockingQueue实现一个去重的优先级队列
PriorityBlockingQueue用最小(大)堆实现,查找操作需要遍历整个堆,时间复杂度O(n)不太符合要求

3.用排序结构实现(如TreeSet,ConcurrentSkipListSet),出队列操作选取排序第一个元素,元素入队列则直接插入

这里选用第三种方法。
由于TreeSet没有提供最大长度限制,且取元素操作是非阻塞的,不符合项目需求,在这里进行简单的修改。
1.添加capacity属性,限制长度
2.添加notEmpty Condition,TreeSet为空时阻塞take操作,添加元素时signalAll

代码

import java.util.Comparator;import java.util.TreeSet;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.ReentrantLock;/** * 支持并发的有限队列,且保证元素唯一 * @Author peng.liu * @Date 17-1-16 */public class ConcurrentPriorityUniqueQueue<T> {    private TreeSet<T> treeSet = null;    private int capacity;    private ReentrantLock lock;    private final Condition notEmpty;    /**     * 构造器     * @param capacity 容量     * @param comparator 比较器     */    public ConcurrentPriorityUniqueQueue(int capacity, Comparator<T> comparator){        if(capacity <= 0){            throw new IllegalArgumentException("queue capacity <= 0");        }        treeSet = new TreeSet<T>(comparator);        this.capacity = capacity;        this.lock = new ReentrantLock();        this.notEmpty = lock.newCondition();    }    /**     * 添加元素,即时返回     * @param element     * @return     */    public boolean offer(T element) {        lock.lock();        try {            if (treeSet.size() == capacity) {                return false;            } else {                treeSet.add(element);                notEmpty.signalAll();                return true;            }        } finally {            lock.unlock();        }    }    /**     * 获取优先队列队头,阻塞     * @return     * @throws InterruptedException     */    public T take() throws InterruptedException{        lock.lockInterruptibly();        try{            while(treeSet.size() == 0){                notEmpty.await();            }            return treeSet.pollFirst();        }finally {            lock.unlock();        }    }    public int size(){        return treeSet.size();    }}

注意

TreeSet根据传入的Comparator判断元素是否相等,对于一些优先级相等但实际不相同的元素在compare时注意下操作

0 0
原创粉丝点击