手写链表阻塞队列的添加和获取功能 ✨ 每日积累

简介: 手写链表阻塞队列的添加和获取功能 ✨ 每日积累
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class LinkedBlockingQueueTest<E> {
    //添加数据时的锁
    private final ReentrantLock putLock = new ReentrantLock();
    //获取数据时的锁
    private final ReentrantLock getLock = new ReentrantLock();
    //容器容量
    private final int capacity;
    //当前元素总数量
    private final AtomicInteger currentElementCount = new AtomicInteger();
    //一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。
    //尾巴节点
    private transient Node<E> last;
    //头节点
    transient Node<E> head;
    /**
     * Condition是在java 1.5中才出现的,它用来替代传统的Object的wait()、notify()实现线程间的协作,
     * 相比使用Object的wait()、notify(),使用Condition的await()、signal()这种方式实现线程间协作更加安全和高效。
     */
    //等待拿数据的等待队列
    private Condition notNull = getLock.newCondition();
    //等待添加数据的等待队列
    private Condition notFull = putLock.newCondition();
    public void put(E element) throws InterruptedException{
        if (element == null) throw new InterruptedException();
        int count = -1;
        Node<E> currentNeedAddNode = new Node<>(element);
        final ReentrantLock putLock = this.putLock;
        final AtomicInteger currentElementCount = this.currentElementCount;
        //上锁
        putLock.lockInterruptibly();
        try{
            //当前元素数量等于容量大小时线程等待
            while (currentElementCount.get() == capacity){
                notFull.await();
            }
            enqueue(currentNeedAddNode);
            count = currentElementCount.incrementAndGet();
            if (count + 1 < capacity) //唤醒
                notFull.signal();
        }finally {
            //锁释放
            putLock.unlock();
        }
        if (count == 0) signalNotEmpty();
    }
    public E get() throws InterruptedException {
        E getElement;
        int count = -1;
        final ReentrantLock getLock = this.getLock;
        final AtomicInteger currentElementCount = this.currentElementCount;
        //上锁
        getLock.lockInterruptibly();
        try {
            while (currentElementCount.get() == 0){
                //等待
                notNull.await();
            }
            getElement = dequeue();
            count = currentElementCount.getAndDecrement();
            if (count > 1) //唤醒
                notNull.signal();
        }finally {
            getLock.unlock();
        }
        if (count == capacity)
            signalNotFull();
        return getElement;
    }
    //当获取数据时发出等待信号,一般不会阻塞添加数据
    private void signalNotEmpty() {
        final ReentrantLock getLock = this.getLock;
        getLock.lock();
        try {
            notNull.signal();
        }finally {
            getLock.unlock();
        }
    }
    //添加数据时的等待信号,一般不会阻塞获取数据
    private void signalNotFull() {
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            notFull.signal();
        } finally {
            putLock.unlock();
        }
    }
    //从尾节点插入
    private void enqueue(Node<E> element){
        last.next = element;
        last = last.next;
    }
    //获取头节点元素并移除
    private E dequeue() {
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h;
        head = first;
        E x = first.item;
        first.item = null;
        return x;
    }
    public LinkedBlockingQueueTest() {
        this(Integer.MAX_VALUE);
    }
    public LinkedBlockingQueueTest(int size) {
        if (size <= 0) throw new IllegalArgumentException();
        this.capacity = size;
        //给头节点尾节点初始化
        head = new Node<>(null);
        last = head;
    }
    /**
     * 链表节点类
     * @param <E>
     */
    static class Node<E> {
        E item;
        //真正的后续节点,如果head.next = null,表示没有后续节点(这是最后一个节点)
        Node<E> next;
        Node(E x) {
            item = x;
        }
    }
}
相关文章
|
安全
基于链表的有界阻塞队列 —— LinkedBlockingQueue
上一节看了基于数据的有界阻塞队列 ArrayBlockingQueue 的源码,通过阅读源码了解到在 ArrayBlockingQueue 中入队列和出队列操作都是用了 ReentrantLock 来保证线程安全。下面咱们看另一种有界阻塞队列:LinkedBlockingQueue。
148 0
|
算法 安全 Java
【Java数据结构及算法实战】系列010:Java队列04——链表实现的阻塞队列LinkedBlockingQueue
【Java数据结构及算法实战】系列010:Java队列04——链表实现的阻塞队列LinkedBlockingQueue
119 0
|
3天前
|
算法
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
LeetCode刷题---19. 删除链表的倒数第 N 个结点(双指针-快慢指针)
|
3天前
|
存储
LeetCode刷题---817. 链表组件(哈希表)
LeetCode刷题---817. 链表组件(哈希表)
|
3天前
|
存储 C语言 索引
环形链表、环形链表 II、有效的括号​​​​​​​【LeetCode刷题日志】
环形链表、环形链表 II、有效的括号​​​​​​​【LeetCode刷题日志】
|
3天前
【移除链表元素】LeetCode第203题讲解
【移除链表元素】LeetCode第203题讲解
|
3天前
|
算法 安全 数据处理
LeetCode刷题---707. 设计链表(双向链表-带头尾双结点)
LeetCode刷题---707. 设计链表(双向链表-带头尾双结点)
|
3天前
leetcode代码记录(移除链表元素
leetcode代码记录(移除链表元素
10 0
【每日一题】LeetCode——链表的中间结点
【每日一题】LeetCode——链表的中间结点
|
3天前
|
C++
[leetcode 链表] 反转链表 vs 链表相交
[leetcode 链表] 反转链表 vs 链表相交