我是靠谱客的博主 包容春天,最近开发中收集的这篇文章主要介绍【JUC源码专题】LinkedBlockingDeque 源码分析(JDK8),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

    • 用法介绍
    • 核心属性
    • 构造方法
    • putFirst(E e)
      • linkFirst
    • putLast
      • linkLast
    • takeFirst()
      • unlinkFirst()
    • takeLast()
      • unlinkLast()
    • contains

LinkedBlockingDeque 是基于链表实现的双端阻塞队列,我们可以从队列的头部和尾部插入或者读取元素。
LinkedBlockingDeque 和 ArrayBlockingQueue 都是使用一把锁保证线程安全。
LinkedBlockingDeque 和 LinkedBlockingQueue 相比,增加了在头尾的插入和删除,但是用的是一把锁。因为 LinkedBlockingDeque 默认 head 和 last 都是 null,且首位均可进行插入和删除,所以不像 LinkedBlockingQueue,可以通过一个 Count 和哨兵结点 head 实现 take 和 put 两把锁。

用法介绍

import java.util.concurrent.LinkedBlockingDeque;

public class TestQueue {
    public static void main(String[] args) throws InterruptedException {
        LinkedBlockingDeque<Integer> deque = new LinkedBlockingDeque<>(8);
        deque.putFirst(1);
        deque.getFirst();
        deque.putLast(2);
        deque.getLast();
    }
}

核心属性

    static final class Node<E> {
        E item;
        Node<E> prev;
        Node<E> next;
        Node(E x) {
            item = x;
        }
    }
    
    // 链表头结点
    transient Node<E> first;

    // 链表尾结点
    transient Node<E> last;

    // 队列中元素的个数
    private transient int count;

    // 队列最大容量
    private final int capacity;

    // 全局锁
    final ReentrantLock lock = new ReentrantLock();

    // 用于等待队列为非空的条件变量(take 时队列空了,就要等到队列为非空时再进行 take)
    private final Condition notEmpty = lock.newCondition();

    // 用于等待队列为非满的条件变量(put 时队列满了,就要等到队列为非满时再进行 put)
    private final Condition notFull = lock.newCondition();

构造方法

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

putFirst(E e)

    public void putFirst(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            // 插入失败则等待在非满的条件变量上,直到插入成功
            while (!linkFirst(node))
                notFull.await();
        } finally {
            lock.unlock();
        }
    }

linkFirst

    private boolean linkFirst(Node<E> node) {
        // 队列已满
        if (count >= capacity)
            return false;
        Node<E> f = first;
        // 将 node 的 next 指向当前头结点
        node.next = f;
        // 将 node 设置为新的头结点
        first = node;
        // 若尾结点为空,将 node 设置为尾结点
        if (last == null)
            last = node;
        else
            f.prev = node; // 当前头结点的 prev 指向 node
        // 队列元素个数+1
        ++count;
        // 唤醒等待队列非空的线程,即唤醒消费者
        notEmpty.signal();
        return true;
    }

putLast

    public void putLast(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            while (!linkLast(node))
                notFull.await();
        } finally {
            lock.unlock();
        }
    }

linkLast

    private boolean linkLast(Node<E> node) {
        if (count >= capacity)
            return false;
        Node<E> l = last;
        // 将 node 的 prev 指向当前的 last 结点
        node.prev = l;
        // 将 node 设置为新的 last 结点
        last = node;
        // 若头结点为空,则头结点也指向 node
        if (first == null)
            first = node;
        else
            l.next = node; // 否则将当前 last 结点的 next 指向 node
        // 队列元素数量加一
        ++count;
        // 唤醒消费者
        notEmpty.signal();
        return true;
    }

takeFirst()

    public E takeFirst() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E x;
            while ( (x = unlinkFirst()) == null)
                notEmpty.await();
            return x;
        } finally {
            lock.unlock();
        }
    }

unlinkFirst()

    private E unlinkFirst() {
        Node<E> f = first;
        if (f == null)
            return null;
        // 获取头结点的 next 结点 n
        Node<E> n = f.next;
        // 获取头结点的数据
        E item = f.item;
        // 清空对数据的引用
        f.item = null;
        // f 的 next 指向自己,帮助 gc
        f.next = f; // help GC
        // 更新头结点
        first = n;
        // 若 n 为空,则说明此时队列为空,last 指向 null
        if (n == null)
            last = null;
        else
            n.prev = null; // n 的 prev 设置为 null
        // 队列元素数量减一
        --count;
        // 唤醒等待队列为非满的线程,即唤醒生产者
        notFull.signal();
        return item;
    }

takeLast()

    public E takeLast() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            E x;
            // 若队列为空,则线程等待在非空条件上
            while ( (x = unlinkLast()) == null)
                notEmpty.await();
            return x;
        } finally {
            lock.unlock();
        }
    }

unlinkLast()

    private E unlinkLast() {
        Node<E> l = last;
        if (l == null)
            return null;
        // 获取尾结点的 prev 结点 p
        Node<E> p = l.prev;
        // 获取当前尾结点的 item
        E item = l.item;
        // 清空当前尾结点对数据的引用
        l.item = null;
        // 当前尾结点的 prev 指向自己
        l.prev = l; // help GC
        // 更新 p 为新的尾结点
        last = p;
        // 若 p 等于 null,则说明此时链表 unlinkLast 之前就只有一个结点,更新头结点为 null
        if (p == null)
            first = null;
        else
            p.next = null; // 新的尾结点 p 的 next 设置为 null
        // 队列元素数量减一
        --count;
        // 唤醒等待队列非满的线程,即唤醒生产者
        notFull.signal();
        return item;
    }

contains

    public boolean contains(Object o) {
        if (o == null) return false;
        final ReentrantLock lock = this.lock;
        // 获取锁
        lock.lock();
        try {
            // 遍历
            for (Node<E> p = first; p != null; p = p.next)
                if (o.equals(p.item))
                    return true;
            return false;
        } finally {
            lock.unlock();
        }
    }

最后

以上就是包容春天为你收集整理的【JUC源码专题】LinkedBlockingDeque 源码分析(JDK8)的全部内容,希望文章能够帮你解决【JUC源码专题】LinkedBlockingDeque 源码分析(JDK8)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(49)

评论列表共有 0 条评论

立即
投稿
返回
顶部