`

LinkedBlockingDeque 源码分析

阅读更多
    LinkedBlockingDeque是LinkedList通过ReentrantLock来实现线程安全以及阻塞,大部分方法都加了锁。

1. 构造方法

    public LinkedBlockingDeque() {
        this(Integer.MAX_VALUE);
    }

    public LinkedBlockingDeque(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
    }

    public LinkedBlockingDeque(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock lock = this.lock;
        lock.lock(); // Never contended, but necessary for visibility
        try {
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (!linkLast(e)) // 队列已满
                    throw new IllegalStateException("Deque full");
            }
        } finally {
            lock.unlock(); // 释放锁
        }
    }


2. linkFirst和linkLast方法

    // 将e作为首节点。如果已满,返回null
    private boolean linkFirst(E e) {
        // assert lock.isHeldByCurrentThread();
        if (count >= capacity)
            return false;
        Node<E> f = first; // 当前首节点
        Node<E> x = new Node<E>(e, null, f); // 新的首节点
        first = x; // first指向新的首节点
        if (last == null)
            last = x; // 只有一个节点,首尾节点相同
        else
            f.prev = x; // 原首节点的前驱是新的首节点
        ++count;
        notEmpty.signal();
        return true;
    }

    // 将e作为尾节点。如果已满,返回null
    private boolean linkLast(E e) {
        // assert lock.isHeldByCurrentThread();
        if (count >= capacity)
            return false;
        Node<E> l = last; // 当前尾节点
        Node<E> x = new Node<E>(e, l, null); // 新的尾节点
        last = x; // last指向新的尾节点
        if (first == null)
            first = x; // 只有一个节点,首尾节点相同
        else
            l.next = x; // 原尾节点的后继是新的尾节点
        ++count;
        notEmpty.signal(); // 提醒队列非空
        return true;
    }


3. unlink方法系列

    // 删除并返回首节点。如果为空,返回null
    private E unlinkFirst() {
        // assert lock.isHeldByCurrentThread();
        Node<E> f = first; // 当前首节点
        if (f == null)
            return null;
        Node<E> n = f.next; // 新的首节点
        E item = f.item; // 待返回的对象
        f.item = null;
        f.next = f; // help GC
        first = n; // first指向新的节点
        if (n == null)
            last = null;
        else
            n.prev = null;
        --count;
        notFull.signal(); // 提醒队列非满
        return item;
    }

    // 删除并返回尾节点。如果为空,返回null
    private E unlinkLast() {
        // assert lock.isHeldByCurrentThread();
        Node<E> l = last; // 当前尾节点
        if (l == null)
            return null;
        Node<E> p = l.prev; // 新的尾节点
        E item = l.item; // 待删除节点指向的对象
        l.item = null;
        l.prev = l; // help GC

        last = p; // last指向新的尾节点
        if (p == null)
            first = null;
        else
            p.next = null;
        --count;
        notFull.signal(); // 提醒队列非满
        return item;
    }

    void unlink(Node<E> x) {
        // assert lock.isHeldByCurrentThread();
        Node<E> p = x.prev;
        Node<E> n = x.next;
        if (p == null) { // x是首节点
           unlinkFirst();
        } else if (n == null) { // x是尾节点
          unlinkLast();
        } else { // x在中间
            p.next = n;
            n.prev = p;
            x.item = null; // 节点对象被释放
            // Don't mess with x's links. They may still be in use by
            // an iterator.
            --count;
            notFull.signal(); // 提醒队列非满
        }
    }


4. BlockingDeque方法

基本流程:
a. 判断参数是否符合要求:不为null等
b. 加锁
c. 执行link或unlink操作,可能需要等待指定的时间或条件符合
d. 在finally块中释放锁
e. 返回布尔值(是否添加或删除成功)或删除的对象

比如:
    public boolean offerFirst(E e) {
        if (e == null) throw new NullPointerException(); // 判断参数
        final ReentrantLock lock = this.lock;
        lock.lock(); // 加锁
        try {
            return linkFirst(e); // 添加操作
        } finally {
            lock.unlock(); // 释放锁
        }
    }

    public void putFirst(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while (!linkFirst(e))
                notFull.await(); // 在notFull条件上等待,直到被唤醒或中断
        } finally {
            lock.unlock();
        }
    }

    public boolean offerFirst(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 (!linkFirst(e)) {
                if (nanos <= 0)
                    return false;
                nanos = notFull.awaitNanos(nanos); // 有限时的等待
            }
            return true;
        } finally {
            lock.unlock();
        }
    }


5. BlockingQueue的方法

单端队列的方法大概只有双端的一半左右:
    public int remainingCapacity() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return capacity - count;
        } finally {
            lock.unlock();
        }
    }

    public int drainTo(Collection<? super E> c) {
         return drainTo(c, Integer.MAX_VALUE);
    }

    public int drainTo(Collection<? super E> c, int maxElements) {
        if (c == null)
            throw new NullPointerException();
        if (c == this) // c不可以为当前队列
            throw new IllegalArgumentException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int n = Math.min(maxElements, count); // 参数maxElements和队列大小的较小值
            for (int i = 0; i < n; i++) {
                c.add(first.item);   // In this order, in case add() throws.
                unlinkFirst();
            }
            return n;
        } finally {
            lock.unlock();
        }
    }


6. Stack方法

    public void push(E e) {
        addFirst(e);
    }

    public E pop() {
        return removeFirst();
    }


7. Collections方法

    public boolean remove(Object o) {
        return removeFirstOccurrence(o);
    }

    public Object[] toArray() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] a = new Object[count];
            int k = 0;
            for (Node<E> p = first; p != null; p = p.next)
                a[k++] = p.item; // 队列和数组指向相同的对象
            return a;
        } finally {
            lock.unlock();
        }
    }

    public void clear() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            for (Node<E> f = first; f != null; ) {
                f.item = null;
                Node<E> n = f.next;
                f.prev = null;
                f.next = null;
                f = n;
            }
            first = last = null;
            count = 0;
            notFull.signalAll();
        } finally {
            lock.unlock();
        }
    }


8. 迭代器

    private abstract class AbstractItr implements Iterator<E> {
        Node<E> next; // 下个节点
        E nextItem; // 下个节点指向的对象
        private Node<E> lastRet; // 当前节点,由remove方法调用。

        // 指向下个节点,由next()方法调用。
        void advance() {
            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
            lock.lock();
            try {
                // assert next != null;
                Node<E> s = nextNode(next);
                if (s == next) {
                    next = firstNode();
                } else {
                    while (s != null && s.item == null) // 跳过被删除的节点
                        s = nextNode(s);
                    next = s;
                }
                nextItem = (next == null) ? null : next.item;
            } finally {
                lock.unlock();
            }
        }

        public boolean hasNext() {
            return next != null;
        }

        public E next() {
            if (next == null)
                throw new NoSuchElementException();
            lastRet = next; // lastRet指向下个节点,方便remove调用
            E x = nextItem; // x指向下个节点的对象,nextItem在advance方法中会被修改
            advance();
            return x;
        }

        public void remove() {
            Node<E> n = lastRet;
            if (n == null)
                throw new IllegalStateException();
            lastRet = null;

            final ReentrantLock lock = LinkedBlockingDeque.this.lock;
            lock.lock();
            try {
                if (n.item != null)
                    unlink(n); // 删除节点n
            } finally {
                lock.unlock();
            }
        }
    }
分享到:
评论

相关推荐

    Java concurrency集合之LinkedBlockingDeque_动力节点Java学院整理

    Java concurrency之LinkedBlockingDeque详解 LinkedBlockingDeque是Java concurrency包中的一个重要类,它是双向链表实现的双向并发阻塞队列。该阻塞队列同时支持FIFO和FILO两种操作方式,即可以从队列的头和尾同时...

    javabitset源码-JerrySoundCode:杰瑞声码

    bitset源码Java源码分析 基础集合列表 ArrayList (done) Vector (done) LinkedList (done) Stack (done) ReferenceQueue (done) ArrayDeque (done) Set HashSet (done) TreeSet (done) LinkedHashSet (done) BitSet ...

    JavaInterview:最开源的Java技术知识点,以及Java源码分析。为开源贡献自己的一份力

    LinkedBlockingDeque :scroll: 主要介绍LeetCode上面的算法译文,以及面试过程中遇到的实际编码问题总结。 :locked: :file_folder: :laptop: :globe_showing_Asia-Australia: :floppy_disk: :input_latin_...

    java++小型游戏项目(文档与源代码).可用做毕业设计

    6. **文档编写**:项目附带的“详细文档”可能包括需求分析、系统设计、程序流程图等,这有助于学习者学习如何撰写专业的技术文档,提高软件工程素养。 7. **版本控制**:虽然未明确提及,但一个完整的项目通常会...

    汪文君高并发编程实战视频资源全集

     高并发编程第三阶段11讲 AtomicXXXFieldUpdater源码分析及使用场景分析.mp4  高并发编程第三阶段12讲 sun.misc.Unsafe介绍以及几种Counter方案性能对比.mp4  高并发编程第三阶段13讲 一个JNI程序的编写,通过...

    汪文君高并发编程实战视频资源下载.txt

     高并发编程第三阶段11讲 AtomicXXXFieldUpdater源码分析及使用场景分析.mp4  高并发编程第三阶段12讲 sun.misc.Unsafe介绍以及几种Counter方案性能对比.mp4  高并发编程第三阶段13讲 一个JNI程序的编写,通过...

    一个小的java Demo , 非常适合Java初学者学习阅读.rar

    链阻塞双端队列 LinkedBlockingDeque,并发 Map(映射) ConcurrentMap, 并发导航映射 ConcurrentNavigableMap,交换机 Exchanger, 信号量 Semaphore,执行器服务 ExecutorService, 线程池执行者 ThreadPoolExecutor,...

    java 线程池实现多并发队列后进先出

    在Java中,可以使用`java.util.Deque`接口的实现,例如`java.util.concurrent.LinkedBlockingDeque`,它支持双端插入和删除,可以作为线程池的工作队列。 - 在创建`ThreadPoolExecutor`时,可以通过传递`...

    java并发工具包详解

    9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 Exchanger 15. 信号量 Semaphore ...

    java并发工具包 java.util.concurrent中文版用户指南pdf

    9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 Exchanger 15. 信号量 Semaphore ...

    Java并发工具包java.util.concurrent用户指南中英文对照阅读版.pdf

    链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航 映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 Exchanger 15. 信号量 Semaphore ...

    JAVA高并发_学习笔记

    JAVA学习高并发的学习笔记。...BlockingQueue:ArrayBlockingQueue , DelayQueue , LinkedBlockingDeque , LinkedBlockingQueue , LinkedTransferQueue , PriorityBlockingQueue , SynchronousQueue

    java线程大总结.pdf

    在给出的示例中,创建了一个`LinkedBlockingDeque`实例,并尝试向其中添加30个元素,结果同样会因栈满而阻塞。 这些同步机制对于构建高效的并发应用程序至关重要,它们可以帮助避免死锁、减少不必要的线程上下文...

    Java并发工具包java.util.concurrent用户指南中英文对照阅读版

    9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 Exchanger 15. 信号量 Semaphore ...

    java并发包资源

    9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 Exchanger 15. 信号量 Semaphore ...

    LRU算法.zip

    1. 数据结构:LRU Cache 的实现,可能使用了HashMap(用于快速查找)和Deque(如LinkedBlockingDeque或LinkedList,用于保持顺序)相结合的方式。 2. 插入操作:当有新数据插入时,首先检查LRU缓存是否已满。若已满...

    10、阻塞队列BlockingQueue实战及其原理分析.pdf

    ### 10、阻塞队列BlockingQueue 实战及其原理分析 #### 一、阻塞队列概述 阻塞队列(BlockingQueue)是Java语言中`java.util.concurrent`包下提供的一种重要的线程安全队列。它继承自`Queue`接口,并在此基础上...

    线程经典问题代码

    通过查看源码,我们可以深入理解如何实现生产者-消费者模型,包括线程间的同步和通信,以及如何避免常见的并发问题,如死锁、活锁和饥饿等。 总之,生产者-消费者问题是多线程编程中的经典案例,它展示了如何在多个...

    RingBuffer_环形缓冲区_

    例如,Java中的`java.util.concurrent.LinkedBlockingDeque`可以看作是一个环形缓冲区的实现,C++的Boost库提供了`boost::lockfree::ring_buffer`。在实际项目中,根据需求选择合适的库或自定义实现,以优化数据处理...

    java面试题合集

    - **LinkedBlockingDeque**: 双端队列。 - **实现原理**: - 使用`Condition`实现通知机制,以同步队列中的生产者和消费者。 - **非阻塞队列**如`ConcurrentLinkedQueue`使用CAS算法来实现线程安全的操作。 **6. ...

Global site tag (gtag.js) - Google Analytics