数据结构和算法之【阻塞队列】下篇

目录

前言

接口优化

定义抽象类

实现类一:使用单锁来实现

实现类二:使用两把锁来实现


前言

上篇文章中,用单锁实现了一个阻塞队列,可以思考下还有哪些地方可以完善和优化的点,这里提出一个可以完善的点和一个可以性能优化的点

  • 可以完善的地方:新增方法,指定等待时间,如果超过指定时间就不再继续阻塞等待
  • 可以性能优化的地方:单锁实现的方式,存放元素和取出元素的方法用的是同一把锁,当存放元素时不能取出元素,这样就有一定的性能损耗,可以使用两把锁来实现存放和取出元素相互不影响,提升程序性能

接口优化

接口中,新增两个方法

  • 入队时,如果队列已满,最多等待指定时间后不再等待
  • 出队时,如果队列已空,最多等待指定时间后不再等待

阻塞队列接口的完整定义如下:

java 复制代码
package algorithm.blocking.queue;

import java.util.concurrent.TimeUnit;

/**
 * 阻塞队列接口
 */
public interface BlockingQueue {
    /**
     * 入队:当队列满时,会一直阻塞等待到队列不满为止
     */
    void put(Object e) throws InterruptedException;

    /**
     * 入队:可以指定最大等待时间
     */
    boolean offer(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException;

    /**
     * 出队:当队列空时,会一直阻塞等待到队列不空为止
     */
    Object take() throws InterruptedException;

    /**
     * 出队:可以指定最大等待时间
     */
    Object poll(long timeout, TimeUnit timeUnit) throws InterruptedException;

    /**
     * 队列中元素个数
     */
    int size();
}

定义抽象类

java 复制代码
package algorithm.blocking.queue;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 定义基于双向链表实现阻塞队列的抽象类
 */
public abstract class AbstractLinkedListBlockingQueue implements BlockingQueue {
    // 虚拟头节点
    protected Node dummyHead;
    // 虚拟尾节点
    protected Node dummyTail;
    // 元素个数
    protected AtomicInteger size = new AtomicInteger();
    // 默认最大容量
    public static final int DEFAULT_MAX_CAPACITY = Integer.MAX_VALUE - 8;
    // 最大容量
    protected int maxCapacity;

    @Override
    public void put(Object e) throws InterruptedException {
        if (e == null) {
            throw new NullPointerException();
        }
        doEnter(e);
    }

    protected abstract void doEnter(Object e) throws InterruptedException;


    @Override
    public boolean offer(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException {
        if (e == null) {
            throw new NullPointerException();
        }
        if (timeout <= 0) {
            throw new IllegalArgumentException();
        }
        if (timeUnit == null) {
            timeUnit = TimeUnit.MILLISECONDS;
        }
        return doEnter(e, timeout, timeUnit);
    }

    protected abstract boolean doEnter(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException;

    @Override
    public Object take() throws InterruptedException {
        Node node = doOut();
        return node == null ? null : node.val;
    }

    protected abstract Node doOut() throws InterruptedException;

    @Override
    public Object poll(long timeout, TimeUnit timeUnit) throws InterruptedException {
        if (timeout <= 0) {
            throw new IllegalArgumentException();
        }
        if (timeUnit == null) {
            timeUnit = TimeUnit.MILLISECONDS;
        }
        Node node = doOut(timeout, timeUnit);
        return node == null ? null : node.val;
    }

    protected abstract Node doOut(long timeout, TimeUnit timeUnit) throws InterruptedException;

    @Override
    public int size() {
        return size.get();
    }

    // 初始化虚拟头尾节点
    protected void initDummyHeadTailNode() {
        dummyHead = new Node();
        dummyTail = new Node();
        dummyHead.next = dummyTail;
        dummyTail.prev = dummyHead;
    }

    // 尾部添加节点
    protected void addLast(Object e) {
        Node addNode = new Node(e);
        Node prev = dummyTail.prev;
        dummyTail.prev = addNode;
        addNode.next = dummyTail;
        addNode.prev = prev;
        prev.next = addNode;
    }

    // 头部移除节点
    protected Node removeFirst() {
        Node removeNode = dummyHead.next;
        Node next = dummyHead.next.next;
        next.prev = dummyHead;
        dummyHead.next = next;
        removeNode.prev = null;
        removeNode.next = null;
        return removeNode;
    }


    // 数据节点
    protected static class Node {
        Object val;
        Node prev;
        Node next;

        public Node() {
        }

        public Node(Object val) {
            this.val = val;
        }

        public Node(Object val, Node prev, Node next) {
            this.val = val;
            this.prev = prev;
            this.next = next;
        }
    }
}

实现类一:使用单锁来实现

java 复制代码
package algorithm.blocking.queue;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 基于链表和单锁方式实现的阻塞队列
 */
public class SingleLockLinkedListBlockingQueue extends AbstractLinkedListBlockingQueue {
    // 定义一把锁
    private final Lock lock = new ReentrantLock();
    private final Condition putWaits = lock.newCondition();
    private final Condition takeWaits = lock.newCondition();

    public SingleLockLinkedListBlockingQueue() {
        this.maxCapacity = DEFAULT_MAX_CAPACITY;
        initDummyHeadTailNode();
    }

    // 实例化时指定最大容量
    public SingleLockLinkedListBlockingQueue(int maxCapacity) {
        this.maxCapacity = maxCapacity;
        initDummyHeadTailNode();
    }

    @Override
    protected void doEnter(Object e) throws InterruptedException {
        lock.lock();
        try {
            while (size.get() == maxCapacity) {
                // 队列已满,线程阻塞等待在putWaits
                putWaits.await();
            }
            addLast(e);
            size.getAndIncrement();
            // 唤醒阻塞在takeWaits上的等待线程
            takeWaits.signalAll();
        } finally {
            lock.unlock();
        }
    }

    @Override
    protected boolean doEnter(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException {
        lock.lock();
        try {
            timeout = timeUnit.toNanos(timeout);
            while (size.get() == maxCapacity) {
                if (timeout <= 0) {
                    return false;
                }
                timeout = putWaits.awaitNanos(timeout);
            }
            addLast(e);
            size.getAndIncrement();
            takeWaits.signalAll();
            return true;
        } finally {
            lock.unlock();
        }
    }

    @Override
    protected Node doOut() throws InterruptedException {
        lock.lock();
        try {
            while (size.get() == 0) {
                // 队列中没有元素,线程阻塞等待在takeWaits
                takeWaits.await();
            }
            Node outNode = removeFirst();
            size.getAndDecrement();
            // 唤醒阻塞在putWaits上的等待线程
            putWaits.signalAll();
            return outNode;
        } finally {
            lock.unlock();
        }
    }

    @Override
    protected Node doOut(long timeout, TimeUnit timeUnit) throws InterruptedException {
        lock.lock();
        try {
            timeout = timeUnit.toNanos(timeout);
            while (size.get() == 0) {
                if (timeout <= 0) {
                    return null;
                }
                timeout = takeWaits.awaitNanos(timeout);
            }
            Node outNode = removeFirst();
            size.getAndDecrement();
            putWaits.signalAll();
            return outNode;
        } finally {
            lock.unlock();
        }
    }
}

实现类二:使用两把锁来实现

java 复制代码
package algorithm.blocking.queue;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 基于链表和双锁方式实现的阻塞队列
 */
public class DoubleLockLinkedListBlockingQueue extends AbstractLinkedListBlockingQueue {
    // 定义双锁
    private final Lock putLock = new ReentrantLock();
    private final Condition putWaits = putLock.newCondition();

    private final Lock takeLock = new ReentrantLock();
    private final Condition takeWaits = takeLock.newCondition();

    public DoubleLockLinkedListBlockingQueue() {
        this.maxCapacity = DEFAULT_MAX_CAPACITY;
        initDummyHeadTailNode();
    }

    public DoubleLockLinkedListBlockingQueue(int maxCapacity) {
        this.maxCapacity = maxCapacity;
        initDummyHeadTailNode();
    }

    @Override
    protected void doEnter(Object e) throws InterruptedException {
        int count;
        putLock.lock();
        try {
            while (size.get() == maxCapacity) {
                // 队列已满,阻塞当前线程
                putWaits.await();
            }
            // 入队
            addLast(e);
            count = size.getAndIncrement();
            if (count < maxCapacity - 1) {
                // 极联唤醒
                putWaits.signal();
            }
        } finally {
            putLock.unlock();
        }
        // 处于临界条件下,唤醒阻塞等待在takeWaits的线程
        // 此处临界条件为:队列中的元素从无到有
        if (count == 0) {
            takeSignal();
        }
    }

    private void takeSignal() {
        takeLock.lock();
        try {
            takeWaits.signal();
        } finally {
            takeLock.unlock();
        }
    }

    @Override
    protected boolean doEnter(Object e, long timeout, TimeUnit timeUnit) throws InterruptedException {
        int count;
        putLock.lock();
        try {
            timeout = timeUnit.toNanos(timeout);
            while (size.get() == maxCapacity) {
                if (timeout <= 0) {
                    return false;
                }
                timeout = putWaits.awaitNanos(timeout);
            }
            addLast(e);
            count = size.getAndIncrement();
            if (count < maxCapacity - 1) {
                putWaits.signal();
            }
        } finally {
            putLock.unlock();
        }
        if (count == 0) {
            takeSignal();
        }
        return true;
    }

    @Override
    protected Node doOut() throws InterruptedException {
        Node outNode;
        int count;
        takeLock.lock();
        try {
            while (size.get() == 0) {
                // 队列为空,当前线程阻塞等待在takeWaits
                takeWaits.await();
            }
            // 出队
            outNode = removeFirst();
            count = size.getAndDecrement();
            if (count > 1) {
                // 极联唤醒
                takeWaits.signal();
            }
        } finally {
            takeLock.unlock();
        }
        // 临界条件:队列从满到不满
        if (count == maxCapacity) {
            putSignal();
        }
        return outNode;
    }

    private void putSignal() {
        putLock.lock();
        try {
            putWaits.signal();
        } finally {
            putLock.unlock();
        }
    }

    @Override
    protected Node doOut(long timeout, TimeUnit timeUnit) throws InterruptedException {
        Node outNode;
        int count;
        takeLock.lock();
        try {
            timeout = timeUnit.toNanos(timeout);
            while (size.get() == 0) {
                if (timeout <= 0) {
                    return null;
                }
                timeout = takeWaits.awaitNanos(timeout);
            }
            outNode = removeFirst();
            count = size.getAndDecrement();
            if (count > 1) {
                takeWaits.signal();
            }
        } finally {
            takeLock.unlock();
        }
        if (count == maxCapacity) {
            putSignal();
        }
        return outNode;
    }
}
相关推荐
啥咕啦呛2 小时前
跟着AI学java第4天:面向对象编程巩固
java·开发语言·人工智能
lThE ANDE2 小时前
Spring Boot--@PathVariable、@RequestParam、@RequestBody
java·spring boot·后端
Treh UNFO2 小时前
Spring Boot环境配置
java·spring boot·后端
NaMM CHIN2 小时前
Spring boot整合quartz方法
java·前端·spring boot
艾莉丝努力练剑2 小时前
【Linux线程】Linux系统多线程(一):线程概念
java·linux·运维·服务器·开发语言·学习·线程
无籽西瓜a2 小时前
【西瓜带你学设计模式 | 第十期 - 外观模式】外观模式 —— 子系统封装实现、优缺点与适用场景
java·后端·设计模式·软件工程·外观模式
@Mr.h2 小时前
(源码)基于Spring Boot + Vue志愿者服务平台的设计与实现
java·vue.js·spring boot·后端
C语言小火车2 小时前
Linux 操作系统八股文(2026最新完整版)
java·linux·运维