PriorityBlockingQueue+DelayQueue

java并发编程之美 学习笔记

PriorityBlockingQueue

PriorityBlockingQueue是带优先级的、无界的、阻塞队列,每次出队都返回优先级最高或者最低的元素。
结构

public class PriorityBlockingQueue<E> extends AbstractQueue<E>
    implements BlockingQueue<E>, java.io.Serializable {

    //默认容量为 11
    private static final int DEFAULT_INITIAL_CAPACITY = 11;

    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

    //存放队列元素
    private transient Object[] queue;

    //队列元素个数
   private transient int size;

    //优先级比较器
    private final Comparator<? super E> comparator;

   
    private final ReentrantLock lock;
    private final Condition notEmpty;

    /**
     * allocationspi nLock 是个自旋锁,其使用 CAS 操作来保证同时只有一个线程可以扩容队列
     * 0: 当前没有正在进行扩容
     * 1:当前正在进行扩容
     */
    private transient volatile int allocationSpinLock;


    private PriorityQueue<E> q;
}

初始化

 public PriorityBlockingQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

    public PriorityBlockingQueue(int initialCapacity) {
        this(initialCapacity, null);
    }


    public PriorityBlockingQueue(int initialCapacity,
                                 Comparator<? super E> comparator) {
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.comparator = comparator;
        this.queue = new Object[initialCapacity];
    }


    public PriorityBlockingQueue(Collection<? extends E> c) {
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();

        // 如果不知道是否已经排序,则为true, 表示需要进行排序操作
        boolean heapify = true; 

        // 如果必须筛选空值,则为true
        boolean screen = true;  


        if (c instanceof SortedSet<?>) {
            SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
            this.comparator = (Comparator<? super E>) ss.comparator();
            heapify = false;
        }
        else if (c instanceof PriorityBlockingQueue<?>) {
            PriorityBlockingQueue<? extends E> pq =
                (PriorityBlockingQueue<? extends E>) c;
            this.comparator = (Comparator<? super E>) pq.comparator();
            screen = false;
            if (pq.getClass() == PriorityBlockingQueue.class) // exact match
                heapify = false;
        }

        Object[] a = c.toArray();
        int n = a.length;
        // If c.toArray incorrectly doesn't return Object[], copy it.
        if (a.getClass() != Object[].class)
            a = Arrays.copyOf(a, n, Object[].class);


        if (screen && (n == 1 || this.comparator != null)) {
            for (int i = 0; i < n; ++i)
                if (a[i] == null)
                    throw new NullPointerException();
        }
        this.queue = a;
        this.size = n;
        if (heapify)
            heapify();
    }

offer

public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        //获取锁
        lock.lock();
        int n, cap;
        Object[] array;

        while ((n = size) >= (cap = (array = queue).length))
        	//1.如果元素个数 >= 队列容量 -- 扩容
            tryGrow(array, cap);

        try {
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
            	//2.通过默认比较器
                siftUpComparable(n, e, array);
            else
            	//通过自定义比较器
                siftUpUsingComparator(n, e, array, cmp);
            //队列元素个数+1, 
            size = n + 1;

            //激活 notEmpty.await()的 一个线程
            notEmpty.signal();
        } finally {
        	//释放锁
            lock.unlock();
        }
        return true;
    }



    //1.队列扩容
    private void tryGrow(Object[] array, int oldCap) {
        lock.unlock(); //第一步释放锁

        Object[] newArray = null;
        //allocationSpinLock == 0 ,表示当前没有线程在进行扩容操作
        //cas操作更新 allocationSpinLock ,将其更新为1,表示已有线程在进行扩容操作。
        if (allocationSpinLock == 0 &&
            UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,
                                     0, 1)) {
            try {
                int newCap = oldCap + ((oldCap < 64) ?
                                       (oldCap + 2) : // grow faster if small
                                       (oldCap >> 1));
                if (newCap - MAX_ARRAY_SIZE > 0) {    // possible overflow
                    int minCap = oldCap + 1;
                    if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
                        throw new OutOfMemoryError();
                    newCap = MAX_ARRAY_SIZE;
                }
                if (newCap > oldCap && queue == array)
                	//初始化newArray 大小
                    newArray = new Object[newCap];
            } finally {
                allocationSpinLock = 0;
            }
        }

        //方法第一行释放锁,导致会有多个线程进行tryGrow这段代码,
        //但是cas操作 保证只有一个线程会 初始化newArray 成功;
        //其他线程 执行到此时,若newArray == null,则让出cpu
        if (newArray == null) 
            Thread.yield();

        //重新上锁
        lock.lock();
        if (newArray != null && queue == array) {
            queue = newArray;
            //copy数组
            System.arraycopy(array, 0, newArray, 0, oldCap);
        }
    }
 	


 	//2.默认比较器
 	/*
 	 * @param k the position to fill
     * @param x the item to insert
     * @param array the heap array
     */
	 private static <T> void siftUpComparable(int k, T x, Object[] array) {
        Comparable<? super T> key = (Comparable<? super T>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = array[parent];
            if (key.compareTo((T) e) >= 0)
                break;
            array[k] = e;
            k = parent;
        }
        array[k] = key;
    }

put
put 操作内部调用的是 offer 操作 ,由 于是无界队列,所以不需要阻塞。

  public void put(E e) {
        offer(e); // never need to block
    }

poll
poll 操作的作用是获取队列内部堆树的根节点元素,如果队列为空 ,则 返回 null 。

   public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return dequeue();
        } finally {
            lock.unlock();
        }
    }


    private E dequeue() {
        int n = size - 1;
        if (n < 0)
            return null;
        else {
            Object[] array = queue;
            E result = (E) array[0];
            E x = (E) array[n];
            array[n] = null;
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftDownComparable(0, x, array, n);
            else
                siftDownUsingComparator(0, x, array, n, cmp);
            size = n;
            return result;
        }
    }

    /*
     * @param k the position to fill
     * @param x the item to insert
     * @param array the heap array
     * @param n heap size
     */
    private static <T> void siftDownComparable(int k, T x, Object[] array,
                                               int n) {
        if (n > 0) {
            Comparable<? super T> key = (Comparable<? super T>)x;
            int half = n >>> 1;           // loop while a non-leaf
            while (k < half) {
                int child = (k << 1) + 1; // assume left child is least
                Object c = array[child];
                int right = child + 1;
                if (right < n &&
                    ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
                    c = array[child = right];
                if (key.compareTo((T) c) <= 0)
                    break;
                array[k] = c;
                k = child;
            }
            array[k] = key;
        }
    }

take
take 操作的作用是获取队列内部堆树的根节点元素 , 如果队列为空则阻塞

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        E result;
        try {
            while ( (result = dequeue()) == null)
                notEmpty.await();
        } finally {
            lock.unlock();
        }
        return result;
    }

size
计算 队列元素个数 。 如下代码在返回 size 前加了锁,以保证在调用 size() 方法时不会有其他线程进行入队和出队操作 。

    public int size() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return size;
        } finally {
            lock.unlock();
        }
    }

demo

public class PriorityBlockingQueueTest {
	static class MyTask implements Comparable<MyTask> {
		private int priority ;
		private String taskName;

		public MyTask(int priority, String taskName) {
			this.priority = priority;
			this.taskName = taskName;
		}

		public int getPriority() {
			return priority;
		}

		public void setPriority(int priority) {
			this.priority = priority;
		}

		public String getTaskName() {
			return taskName;
		}

		public void setTaskName(String taskName) {
			this.taskName = taskName;
		}

		@Override
		public int compareTo(MyTask o) {
			return this.priority - o.getPriority();
		}

		public void doSth(){
			System.out.println(taskName +" : " +priority);
		}
	}

	public static void main(String[] args) {
		PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<MyTask>();
		IntStream.rangeClosed(1,10).forEach(index -> {
			queue.add(new MyTask(new Random().nextInt(10), "TASK_" + index));
		});

		while(!queue.isEmpty()){
			MyTask task = queue.poll();
			if(task != null){
				task.doSth();
			}
		}

		System.out.println("=============END=============");
	}

}

运行结果:
在这里插入图片描述

从结果可知 ,任务执行的先后顺序和它们被放入队列的先后顺序没有关系,而是和它
们的优先级有关系。



DelayQueue

DelayQueue并发队列是 一个无界的、阻塞延迟队 列 ,队列中的每个元素都有个过期时间.当从队列获取元素时,只有过期元素才会出队列。队列头元素是最快要过期的元素。

结构

public class DelayQueue<E extends Delayed> extends AbstractQueue<E>
    implements BlockingQueue<E> {

	// ReentrantLock 实现线程同步
	private final transient ReentrantLock lock = new ReentrantLock();
	
	//DelayQueue 内部使用 PriorityQueue 存放数据
	//队列里面的元素要实现 Delayed 接口
    private final PriorityQueue<E> q = new PriorityQueue<E>();

    private Thread leader = null;

    private final Condition available = lock.newCondition();
}

Delayed

//继承了Comparable接口: 通常使用delay来确定顺序优先级;
public interface Delayed extends Comparable<Delayed> {
	//获取当前元素还有多少过期时间
    long getDelay(TimeUnit unit);
}

public class DelayedQueueTest {
	static class DelayedEle implements Delayed {
		private final long delayTime ; //延迟时间
		private final long expire  ; //到期时间
		private String taskName  ; //任务名称

		public DelayedEle(long delayTime, String taskName) {
			this.delayTime = delayTime;
			this.taskName = taskName;

			expire = System.currentTimeMillis() + delayTime;
		}

		//剩余时间=到期时间 - 当前时间
		@Override
		public long getDelay(TimeUnit unit) {
			return unit.convert(this.expire - System.currentTimeMillis(),TimeUnit.MILLISECONDS );
		}

		//优先级队列的 比较规则
		@Override
		public int compareTo(Delayed o) {
			return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));
		}

		@Override
		public String toString() {
			return "DelayedEle{" +
					"delayTime=" + delayTime +
					", expire=" + expire +
					", taskName='" + taskName + '\'' +
					'}';
		}
	}

	public static void main(String[] args) throws InterruptedException {
		DelayQueue<DelayedEle> queue = new DelayQueue<>();
		IntStream.rangeClosed(1,10).forEach(index -> {
			queue.offer(new DelayedEle(new Random().nextInt(500), "TASK_" + index));
		});

		DelayedEle temp ;
		while((temp = queue.take()) != null){
			System.out.println(System.currentTimeMillis() + "-----" +temp);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值