`
wubo.wb
  • 浏览: 28706 次
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论
阅读更多

LinkedBlockingQueue是一个线程安全的阻塞队列,它实现了BlockingQueue接口,BlockingQueue接口继承自java.util.Queue接口,并在这个接口的基础上增加了take和put方法,这两个方法正是队列操作的阻塞版本。

 

LinkedBlockingQueue

首先看看LinkedBlockingQueue的类图

从图中可以看出LinkedBlockingQueue中引入了两把锁takeLock和putLock,显然分别是用于take操作和put操作的。既LinkedBlockingQueue入队和出队用的是不同的锁,那么LinkedBlockingQueue可以同时进行入队和出队操作。

同时,还引入了两个条件变量,notEmpty和notFull,参照生产者消费者模型,当队列不空的时候消费者可以消费,当队列不满的时候,生产者可以生产。所以notEmpty是告诉程序现在队列中有元素,可以执行take操作;notFull告诉程序队列还没满,还可以往里面放。

类图中还有一个count字段,是记录队列中结点个数的,因此对于LinkedBlockingQueue来说,获取队列的size时间复杂度为o(1),capacity为队列的容量,head和last指针分别指向队头和队尾元素。

 

入队操作

    public void put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();//1
        int c = -1;
        Node<E> node = new Node(e);
        final ReentrantLock putLock = this.putLock;
        final AtomicInteger count = this.count;
        putLock.lockInterruptibly();
        try {
            while (count.get() == capacity) {//2
                notFull.await();
            }
            enqueue(node);//3
            c = count.getAndIncrement();//4
            if (c + 1 < capacity)
                notFull.signal();//5
        } finally {
            putLock.unlock();
        }
        if (c == 0)
            signalNotEmpty();//6
    }

1、首先检查需要入队的元素是否为空,若为空抛出InterruptedException异常(1处所示);

2、然后获取putLock锁,判断队列是否已满,如果已满就挂起当前线程,直到notFull这个条件满足(2处所示);

3、到此表明队列未满,可以入队,和普通入队操作一样(3所示);

4、入队后将队列count+1,count采用的是AtomicInteger的原子操作(4所示);

5、再次判断是否已满,如果未满就通知其他线程(5所示)

6、执行完以上步骤后就解putLock锁。c默认为-1,加入队列后结果为0,说明之前队列为空。由于此时锁还在当前线程上,所以不可能出队,也不可能入队,那么在队列不为空的时候就需要安全的唤醒一个出队线程了。

以上就是入队操作的全过程,LinkedBlockingQueue还有非阻塞版本的入队操作:步骤和put操作类似,但也有一些区别:

public boolean add(E e) 在入队不成功的时候会抛出异常;

public boolean offer(E e)不会抛出异常,而是直接返回true or false

 

offer(E e,  long timeout,TimeUnit unit) throws InterruptedException超时版本的offer也是返回true or false。如果在指定时间范围内没有入队成功会阻塞,直到超时抛出异常。

 

出队操作

    public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
                notEmpty.await();//1
            }
            x = dequeue();//2
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();//3
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();//4
        return x;
    }

 

1、首先获取takeLock锁,然后判断队列中是否有元素,如果没有元素就阻塞,直到notEmpty条件出现(1所示)

2、然后出队(2所示)

3、出队之后判断队列中是否还有元素,如果还有就发出notEmpty通知其他线程(3所示)

4、执行以上步骤后,表明成功出队,释放takeLock锁。然后发出队列不空的信号。

和入队一样,出队操作也有非阻塞版本,与入队操作一一对应,这里不作分析。

 

总结

LinkedBlockingQueue是基于链表的队列的阻塞版本,它实现了入队出队分离,效率比较高,而且支持容量限制。但由于它采用的是链表,所以在查找元素时效率一般。

 

分享到:
评论

相关推荐

    linkedblockingqueue

    《LinkedBlockingQueue深度解析与应用实践》 在Java并发编程领域,`LinkedBlockingQueue`是一个不可或缺的工具。作为`java.util.concurrent`包中的一个线程安全的队列,它基于链表结构实现,具备先进先出(FIFO)的...

    LinkedBlockingQueue 和 ConcurrentLinkedQueue的区别.docx

    《LinkedBlockingQueue与ConcurrentLinkedQueue的比较与应用》 在Java并发编程中,队列是一种重要的数据结构,尤其在多线程环境下的任务调度和数据传递中扮演着关键角色。LinkedBlockingQueue和...

    LinkedBlockingQueue + 单向链表基本结构

    《深入理解LinkedBlockingQueue与单向链表结构》 LinkedBlockingQueue是Java并发包`java.util.concurrent`中的一个先进先出(FIFO)队列,它基于链表结构实现,特别适用于高并发场景。该队列的主要特点是其内部数据...

    并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法

    ### 并发队列 ConcurrentLinkedQueue 和阻塞队列 LinkedBlockingQueue 用法详解 #### 一、并发队列 ConcurrentLinkedQueue 概述 `ConcurrentLinkedQueue` 是 Java 并发包 `java.util.concurrent` 提供的一个高性能...

    LinkedBlockingQueuejava.pdf

    《LinkedBlockingQueue in Java》 Java中的`LinkedBlockingQueue`是`java.util.concurrent`包下的一种线程安全的阻塞队列,它是基于链表结构实现的,具有很好的性能表现。这种队列在多线程环境下的并发操作中被广泛...

    并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解

    "并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解" ArrayBlockingQueue和LinkedBlockingQueue是Java并发容器中两个常用的阻塞队列实现,分别基于数组和链表存储元素。它们都继承自AbstractQueue类...

    JDK容器学习之Queue:LinkedBlockingQueue

    本篇文章将深入探讨`LinkedBlockingQueue`,这是一个基于链表结构的无界阻塞队列,常用于线程池的创建中作为任务缓冲队列。 首先,我们来看一下`LinkedBlockingQueue`的底层数据结构。与数组结构的`...

    元素唯一的LinkedBlockingQueue阻塞队列

    《元素唯一的LinkedBlockingQueue阻塞队列》 在Java并发编程中,`LinkedBlockingQueue`是一种基于链表结构的阻塞队列,它在多线程环境下的性能表现优秀,常用于实现生产者消费者模型。这个队列的一个关键特性是其...

    生产者/消费者模式 阻塞队列 LinkedBlockingQueue

    在Java中,阻塞队列(BlockingQueue)是一个很好的实现生产者/消费者模式的工具,而LinkedBlockingQueue则是Java并发包(java.util.concurrent)中提供的一个具体实现。 LinkedBlockingQueue是一个基于链表结构的...

    详细分析Java并发集合LinkedBlockingQueue的用法

    详细分析Java并发集合LinkedBlockingQueue的用法 Java并发集合LinkedBlockingQueue是Java并发集合中的一种阻塞队列实现,使用链表方式实现的阻塞队列。LinkedBlockingQueue的实现主要包括链表实现、插入和删除节点...

    java中LinkedBlockingQueue与ArrayBlockingQueue的异同

    Java中的`LinkedBlockingQueue`和`ArrayBlockingQueue`都是`java.util.concurrent`包下的线程安全队列,它们都实现了`BlockingQueue`接口,提供了一种高效、线程安全的数据同步方式。这两种队列在很多方面都有相似之...

    java线程池概念.txt

     ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和Synchronous。线程池的排队策略与BlockingQueue有关。 threadFactory:线程工厂,主要用来创建线程:默认值 ...

    blockingQueues:简单,高性能,goroutine安全队列,可用作资源池或作业队列

    LinkedBlockingQueue :由容器/列表支持的有界阻塞队列 ConcurrentRingBuffer :由片支持的有界无锁队列 安装 go get - u github . com / theodesp / blockingQueues 用法 非阻塞API queue , _ := NewArrayBlock

    spring-blockingqueue:用Spring Boot阻止队列

    通常,我们会选择实现BlockingQueue的类,如ArrayBlockingQueue、LinkedBlockingQueue或PriorityBlockingQueue,根据实际需求选择合适的实现。 例如,我们可以创建一个配置类,如下所示: ```java @Configuration ...

    喜提JDK的BUG一枚!多线程的情况下请谨慎使用这个类的stream遍历。.doc

    《Java多线程环境下慎用`LinkedBlockingQueue`的`stream`遍历——揭秘JDK BUG》 在Java编程中,线程安全是多线程编程的重要考量因素,而`LinkedBlockingQueue`作为Java并发包中的一个线程安全队列,因其高效的性能...

    队列写入mysql实例

    本实例将探讨如何利用`LinkedBlockingQueue`和Redis队列来实现数据写入MySQL的过程,这对于大型系统中的批量数据处理和并发控制具有重要意义。 首先,`LinkedBlockingQueue`是Java并发库`java.util.concurrent`中的...

    操作系统的线程同步实验报告完整版

    在本次实验中,我们深入探讨了多种线程同步的方法,包括synchronized关键字、volatile、ReentrantLock类以及阻塞队列LinkedBlockingQueue。 首先,synchronized关键字是Java中用于实现线程同步的基本手段,它可以...

    java多线程模拟队列实现排队叫号

    private final LinkedBlockingQueue&lt;ClientThread&gt; queue = new LinkedBlockingQueue(); public void enqueue(ClientThread client) { try { queue.put(client); } catch (InterruptedException e) { Thread....

Global site tag (gtag.js) - Google Analytics