自己实现的简易LinkedBlockingQueue阻塞队列

实现基于链表的阻塞队列,并使用两个锁实现同时进行写和读操作:

核心方法:

1、放入数据

  • offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,则返回true,否则返回false.(本方法不阻塞当前执行方法的线程)
  • offer(E o, long timeout, TimeUnit unit):可以设定等待的时间,如果在指定的时间内,还不能往队列中加入BlockingQueue,则返回失败。
  • put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.

2、获取数据

  • poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null;
  • poll(long timeout, TimeUnit unit):从BlockingQueue取出一个队首的对象,如果在指定时间内,队列一旦有数据可取,则立即返回队列中的数据。否则知道时间超时还没有数据可取,返回失败。
  • take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入;
  • drainTo():一次性从BlockingQueue获取所有可用的数据对象(还可以指定获取数据的个数),通过该方法,可以提升获取数据效率;不需要多次分批加锁或释放锁。

实现逻辑:

这里主要实现put和take方法

Put写入数据逻辑:

1、检测队列是否已满,若满则阻塞,否则添加数据,并唤醒另一个写入线程

2、唤醒读取线程

Take读取数据逻辑:

1、检测队列是否为空,若空则阻塞,否则读取数据,并唤醒另一个读取线程

2、唤醒写入线程

注意:并发环境下,队列目前拥有的数据要使用AtomicInteger自增。


import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class MyBlockingQueue<E>   {

    private Node<E> head;
    private Node<E> last;

    private static class Node<E> {
        E item;
        Node<E> next;

        Node(Node<E> prev, E element) {
            this.item = element;
            this.next = next;
        }

        Node(E element) {
            this.item = element;
        }
    }


    /** 队列拥有的元素 */
    private AtomicInteger ac = new AtomicInteger(0);


    /** 队列容量 */
    private int capacity;


    private final ReentrantLock writeLock = new ReentrantLock();
    private final Condition writeSignal = writeLock.newCondition();

    private final ReentrantLock readLock = new ReentrantLock();
    private final Condition readSignal = readLock.newCondition();

    public MyBlockingQueue(int num) {
        this.capacity = num;
        last = head = new Node<E>(null);
    }

    private void callReadLock() {
        readLock.lock();
        readSignal.signal();
        readLock.unlock();
    }

    private void callWriteLock() {
        writeLock.lock();
        writeSignal.signal();
        writeLock.unlock();
    }


    //调用此方法的线程被阻断直到BlockingQueue里面有空间再继续.阻塞
    void put(E i) throws InterruptedException {
        Node<E> node = new Node<E>(i);
        int count = -1;
        writeLock.lockInterruptibly();
        try {
            //若队列已满,则线程阻塞
            while (ac.get() == capacity) {
                writeSignal.await();
            }
            last.next = node;
            last = last.next;
            count = ac.getAndIncrement();
            //队列尚有位置,则发出信号,继续添加元素
            if (count + 1 < capacity)
                writeSignal.signal();
        } finally {
            writeLock.unlock();
        }
        //若队列中有元素,则发出信号,消费元素
        if (count >= 1)
            callReadLock();
    }

    //不阻塞当前执行方法的线程,不阻塞
    void offer(E i) {
    }

    //取不到时阻塞
    E take() throws InterruptedException {
        E x;
        int count = -1;
        readLock.lockInterruptibly();
        try {
            //若队列为空,则阻塞线程
            while (ac.get() == 0) {
                readSignal.await();
            }

            Node<E> h = head;
            Node<E> first = h.next;
            h.next = h;
            head = first;
            x = first.item;
            first.item = null;

            count = ac.getAndDecrement();
            //若队列尚有元素,则唤醒消费线程
            if (count > 1)
                readSignal.signal();
        } finally {
            readLock.unlock();
        }
        //若队列的数据没满,发出信号唤醒添加元素线程
        if (count <= capacity-1)
            callWriteLock();
        return x;
    }

    //取不到时返回null,不阻塞
    E poll() {
        E x;
        readLock.lock();
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h;
        head = first;
        x = first.item;
        first.item = null;
        ac.getAndDecrement();
        readLock.unlock();
        return x;
    }



    int getCount() {
        return ac.get();
    }
}

 测试方法:3个线程写入数据,2个线程读取数据

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MyBlockingQueueTest {

    public static void main(String[] args) throws InterruptedException {
        MyBlockingQueue<String> queue = new MyBlockingQueue<>(100);

        queue.put("第一个元素");

        ExecutorService es = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 3; i++) {
            es.submit(() -> {
                for (int j = 0; j < 10000; j++) {
                    try {
                        queue.put(Thread.currentThread().getName()+":"+j);
//                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        for (int i = 0; i < 2; i++) {
            es.submit(() -> {
                try {
                    while (true) {
                        System.out.println(Thread.currentThread().getName()+"取:"+queue.take());
//                        Thread.sleep(50);
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }


        es.shutdown();

    }
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值