package com.github.ltsopensource.queue; import com.github.ltsopensource.queue.domain.JobPo; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantLock; /** * 优先级 有界 去重 双向队列 * @author Robert HG (254963746@qq.com) on 8/5/16. */ public class JobPriorityBlockingDeque { private final int capacity; private final LinkedList<JobPo> list; private final ReentrantLock lock = new ReentrantLock(); // Key: jobId value:gmtModified private Map<String, Long> jobs = new ConcurrentHashMap<String, Long>(); private Comparator<JobPo> comparator; public JobPriorityBlockingDeque(int capacity) { if (capacity <= 0) throw new IllegalArgumentException(); this.capacity = capacity; this.list = new LinkedList<JobPo>(); this.comparator = new Comparator<JobPo>() { @Override public int compare(JobPo left, JobPo right) { if (left.getJobId().equals(right.getJobId())) { return 0; } int compare = left.getPriority().compareTo(right.getPriority()); if (compare != 0) { return compare; } compare = left.getTriggerTime().compareTo(right.getTriggerTime()); if (compare != 0) { return compare; } compare = left.getGmtCreated().compareTo(right.getGmtCreated()); if (compare != 0) { return compare; } return -1; } }; } public JobPo pollFirst() { lock.lock(); try { JobPo f = list.pollFirst(); if (f == null) return null; jobs.remove(f.getJobId()); return f; } finally { lock.unlock(); } } public JobPo pollLast() { lock.lock(); try { JobPo l = list.pollLast(); if (l == null) return null; jobs.remove(l.getJobId()); return l; } finally { lock.unlock(); } } public boolean offer(JobPo e) { if (e == null) throw new NullPointerException(); if (list.size() >= capacity) return false; lock.lock(); try { if (jobs.containsKey(e.getJobId())) { // 如果已经在内存中了,check下是否和内存中的一致 Long gmtModified = jobs.get(e.getJobId()); if (gmtModified != null && !gmtModified.equals(e.getGmtModified())) { // 删除原来的 removeOld(e); } } int insertionPoint = Collections.binarySearch(list, e, comparator); if (insertionPoint < 0) { // this means the key didn't exist, so the insertion point is negative minus 1. insertionPoint = -insertionPoint - 1; } list.add(insertionPoint, e); jobs.put(e.getJobId(), e.getGmtModified()); return true; } finally { lock.unlock(); } } private void removeOld(JobPo e) { Iterator<JobPo> i = iterator(); int index = 0; while (i.hasNext()) { JobPo o = i.next(); if (o.getJobId().equals(e.getJobId())) { list.remove(index); jobs.remove(e.getJobId()); return; } index++; } } public JobPo poll() { return pollFirst(); } public int size() { lock.lock(); try { return list.size(); } finally { lock.unlock(); } } @Override public String toString() { lock.lock(); try { Iterator<JobPo> i = iterator(); if (!i.hasNext()) return "[]"; StringBuilder sb = new StringBuilder(); sb.append('['); for (; ; ) { JobPo e = i.next(); sb.append(e); if (!i.hasNext()) return sb.append(']').toString(); sb.append(", "); } } finally { lock.unlock(); } } public Iterator<JobPo> iterator() { return list.iterator(); } }