zoukankan      html  css  js  c++  java
  • 各种Queue分析

    Queue主要方法的区别:

      抛出异常 返回特殊值
    插入 add(e)插入成功则返回true,没有可用空间则IllegalStateException offer(e)
    移除 remove(e)获取并移除,不存在则抛异常 poll(e)
    检查 element()获取元素,但并不移除,队列为空则抛出异常 peek()

    Queue既可以是FIFO,也可以是按照一定优先级顺序排列,BlockingQueue区别在于对于空队列获取等待,满队列加入等待,适用于生产者消费者模型:

    /**
     * Created by itworker365 on 6/2/2017.
     */
    public class ThreadWNTest {
        public static void main (String[] args) throws InterruptedException {
            BlockingQueue blockingQueue = new ArrayBlockingQueue(10);
            Thread t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        int i = 0;
                        while (i < 100) {
                            System.out.println("put :" + i++);
                            blockingQueue.put(i++);
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t1.start();
            Thread t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        while (true) {
                            System.out.println("take: " + blockingQueue.take());
                        }
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t2.start();
            System.out.println("start");
        }
    }

    ArrayBlockingQueue: 主要方法学习

    包含一个object数组存放元素,takeIndex和putIndex分别包含放入和取出元素的位置,count表示当前元素个数,全局锁lock分别创建notFull和notEmpty(await/singnal)完成当元素满时添加等待,元素空时取元素等待。

    class BasicBlockingQueue<E> {
        final Object[] items;
        int takeIndex;
        int putIndex;
        int count;
        final ReentrantLock lock;
        private final Condition notEmpty;
        private final Condition notFull;
    
        public BasicBlockingQueue (int capacity, boolean fair){
            this.items = new Object[capacity];
            lock = new ReentrantLock(fair);
            notEmpty = lock.newCondition();
            notFull =  lock.newCondition();
        }
        //添加元素,如果添加元素为null则抛出异常,如果非null则获取全局锁
        // 看添加元素后是否满足队列总长度限制,超出返回false,未超出则将元素添加到对应的items[putIndex]位置,并唤醒notEmpty.signal()
        private boolean offer(E e) {
            if (e == null)
                throw new NullPointerException();
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                if (count == items.length)
                    return false;
                else {
                    enqueue(e);
                    return true;
                }
            } finally {
                lock.unlock();
            }
        }
        //带超时设定的这种
        public boolean offer(E e, long timeout, TimeUnit unit)
                throws InterruptedException {
            if (e == null)
                throw new NullPointerException();
            long nanos = unit.toNanos(timeout);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                while (count == items.length) {
                    if (nanos <= 0)
                        return false;
                    nanos = notFull.awaitNanos(nanos);
                }
                enqueue(e);
                return true;
            } finally {
                lock.unlock();
            }
        }
        //添加元素时,offer如果满了返回false,而add不能添加时则抛出异常
        public boolean add(E e) {
            if (offer(e))
                return true;
            else
                throw new IllegalStateException("Queue full");
        }
    
        private void enqueue(E x) {
            final Object[] items = this.items;
            items[putIndex] = x;
            if (++putIndex == items.length)
                putIndex = 0;
            count++;
            notEmpty.signal();
        }
        //取出元素,带超时的,获取全局锁,当元素为0,等待超时时间,一直没有就返回null,有的话就取出队列元素
        public E poll(long timeout, TimeUnit unit) throws InterruptedException {
            long nanos = unit.toNanos(timeout);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                while (count == 0) {
                    if (nanos <= 0)
                        return null;
                    nanos = notEmpty.awaitNanos(nanos);
                }
                return dequeue();
            } finally {
                lock.unlock();
            }
        }
    
        private E dequeue() {
            final Object[] items = this.items;
            E x = (E) items[takeIndex];
            items[takeIndex] = null;
            //不断循环使用
            if (++takeIndex == items.length)
                takeIndex = 0;
            count--;
            notFull.signal();
            return x;
        }
    }

    LinkedBlockingQueue: 主要方法学习

    元素存放在单向列表中,记录首尾节点,统计元素数目用atomicInteger,takelock和putlock分离,添加只需要修改last,取出只需要修改head

    class BasicLinkedBlockingQueue<E> {
        private final int capacity = Integer.MAX_VALUE;
        //统计元素数目用AtomicInteger
        private final AtomicInteger count = new AtomicInteger(0);
        private transient Node<E> head;
        private transient Node<E> last;
        //分别创建takeLock和putLock
        private final ReentrantLock takeLock = new ReentrantLock();
        private final Condition notEmpty = takeLock.newCondition();
    
        private final ReentrantLock putLock = new ReentrantLock();
        private final Condition notFull = putLock.newCondition();
    
        //加入元素,包含超时,先获取putlock,跟array基本一样,元素数目用count.getAndIncrement()统计,然后释放锁,发放signalNotEmpty通知
        public boolean offer(E e, long timeout, TimeUnit unit)
                throws InterruptedException {
    
            if (e == null) throw new NullPointerException();
            long nanos = unit.toNanos(timeout);
            int c = -1;
            final ReentrantLock putLock = this.putLock;
            final AtomicInteger count = this.count;
            putLock.lockInterruptibly();
            try {
                while (count.get() == capacity) {
                    if (nanos <= 0)
                        return false;
                    nanos = notFull.awaitNanos(nanos);
                }
                enqueue(new Node<E>(e));
                c = count.getAndIncrement();
                if (c + 1 < capacity)
                    notFull.signal();
            } finally {
                putLock.unlock();
            }
            if (c == 0)
                signalNotEmpty();
            return true;
        }
        //取得元素,带超时,先拿到takelock,和别的也一样
        public E poll(long timeout, TimeUnit unit) throws InterruptedException {
            E x = null;
            int c = -1;
            long nanos = unit.toNanos(timeout);
            final AtomicInteger count = this.count;
            final ReentrantLock takeLock = this.takeLock;
            takeLock.lockInterruptibly();
            try {
                while (count.get() == 0) {
                    if (nanos <= 0)
                        return null;
                    nanos = notEmpty.awaitNanos(nanos);
                }
                x = dequeue();
                c = count.getAndDecrement();
                if (c > 1)
                    notEmpty.signal();
            } finally {
                takeLock.unlock();
            }
            if (c == capacity)
                signalNotFull();
            return x;
        }
        //添加只需要修改last
        private void enqueue(Node<E> node) {
            last = last.next = node;
        }
        //取出只需要修改head
        private E dequeue() {
            Node<E> h = head;
            Node<E> first = h.next;
            h.next = h; // help GC
            head = first;
            E x = first.item;
            first.item = null;
            return x;
        }
        private void signalNotEmpty() {
            final ReentrantLock takeLock = this.takeLock;
            takeLock.lock();
            try {
                notEmpty.signal();
            } finally {
                takeLock.unlock();
            }
        }
        private void signalNotFull() {
            final ReentrantLock putLock = this.putLock;
            putLock.lock();
            try {
                notFull.signal();
            } finally {
                putLock.unlock();
            }
        }
    }
    class Node<E> {
        E item;
        Node<E> next;
        Node(E x) { item = x; }
    }
  • 相关阅读:
    SVG的学习(34—36)
    28-30 js 文本全选
    28-30 键盘事件
    react学习(四)之设置 css样式 篇
    跳台阶
    详解Django的CSRF认证
    Django model中数据批量导入bulk_create()
    Redis从入门到精通
    Python的进阶1:copy()与deepcopy()区别
    sql面试题
  • 原文地址:https://www.cnblogs.com/it-worker365/p/6933395.html
Copyright © 2011-2022 走看看