java并发编程 LinkedBlockingDeque详解

这篇具有很好参考价值的文章主要介绍了java并发编程 LinkedBlockingDeque详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


java 并发编程系列文章目录

1 LinkedBlockingDeque是什么

首先queue是一种数据结构,一个集合中,先进后出,有两种实现的方式,数组和链表。从尾部追加,从头部获取。Deque是两端都可以添加,且两端都可以获取,所以它的方法会有一系列的Last,Frist语义,添加或获取等操作会指明哪个方向的,这也是Deque接口的定义。
那如果你不指定语义 如add()方法,他会默认调用addLast
综上所述,LinkedBlockingDeque是一个线程安全的双端阻塞队列。

2 核心属性详解

相对于LinkedBlockingQueue 他只能使用一把锁,不能分成put 和 take两把锁。因为此时双端都可以put 和 take,所以只能使用一个锁,通过锁,对其链表实现线程安全的操作。

	//队列的头尾节点
    transient Node<E> first;
    transient Node<E> last;

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

    //指定的队列的容量,默认Int最大值
    private final int capacity;

    //实现线程安全的使用的锁
    final ReentrantLock lock = new ReentrantLock();

    //获取元素的时候如果空了会使用它让其自己等待
    private final Condition notEmpty = lock.newCondition();

    //添加元素的时候如果满了(count == capacity)会使用它让其自己等待
    private final Condition notFull = lock.newCondition();

3 核心方法详解

下面会列举First系列的方法,因为last系列相对于first只是链表方向不一样,操作都是一致的。

3.1 addFirst(E e)

调用offerFirst 如果未成功 则抛出异常

    public void addFirst(E e) {
        if (!offerFirst(e))
            throw new IllegalStateException("Deque full");
    }

3.2 offerFirst(E e)

在链表的头部添加一个元素,使用ReentrantLock 保证线程安全

    public boolean offerFirst(E e) {
        if (e == null) throw new NullPointerException();
        Node<E> node = new Node<E>(e);
        //获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        	//把当前元素对应的节点放到头结点那里
            return linkFirst(node);
        } finally {
            lock.unlock();
        }
    }
    private boolean linkFirst(Node<E> node) {
    	//如果元素已经超出容量,返回添加失败
        if (count >= capacity)
            return false;
        //链表的操作,用的是双向链表,first变成自己,之前的first是自己的next
        Node<E> f = first;
        node.next = f;
        first = node;
        if (last == null)
            last = node;
        else
            f.prev = node;
        //元素统计数量加1
        ++count;
        //唤醒那些因为获取不到元素而阻塞的线程
        notEmpty.signal();
        return true;
    }

3.3 putFirst(E e)

相对于offer一个元素 如果元素数量已到达容量上线,会阻塞住等待元素被取走才放入
在juc下面 put add take等语义都是一致的

    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();
        }
    }

3.4 removeFirst()

从头结点移除一个元素,调用的是pollFirst,拿出元素返回,元素==null会抛出异常

    public E removeFirst() {
        E x = pollFirst();
        if (x == null) throw new NoSuchElementException();
        return x;
    }

3.5 pollFirst()

取出first元素并返回,会返回null

    public E pollFirst() {
    	//加锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        	// 取出first, 链表的操作和count的维护以及唤醒添加元素因为容量到达上线的等待的线程
            return unlinkFirst();
        } finally {
            lock.unlock();
        }
    }

3.6 takeFirst()

获取一个first元素,区别poll 在于会阻塞等待

    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();
        }
    }

3.7 其他

对于last系列方法,只是链表的操作方向不一样而已
其次默认的不带last 和 first系列的方法,即原始的add put等方法,可以等同LinkedBlockingQueue。
LinkedBlockingDeque内部是一个双向链表,支持了链表两端操作,所以方法不一一介绍,原理都是一样。

4 总结

LinkedBlockingDeque使用双端队列,通过ReentrantLock保证线程安全,实现了双端的线程安全的阻塞队列。文章来源地址https://www.toymoban.com/news/detail-691951.html

到了这里,关于java并发编程 LinkedBlockingDeque详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Java 并发编程】Java 线程本地变量 ThreadLocal 详解

    先一起看一下 ThreadLocal 类的官方解释: 用大白话翻译过来,大体的意思是: ThreadLoal 提供给了 线程局部变量 。同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。这里有几点需要注意: 因为每个 Thread 内有自己的实例副本,且 该副本只能由当前 Thread 使用 。

    2024年02月04日
    浏览(71)
  • 【Java 并发编程】一文详解 Java 内置锁 synchronized

    存在共享数据; 多线程共同操作共享数。 synchronized 可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时 synchronized 可以保证一个线程的变化可见(可见性),即可以代替 volatile。 多线程编程中,有可能会出现多个线程同时访问同一个共享、可变

    2024年02月02日
    浏览(35)
  • java并发编程 AbstractQueuedSynchronizer(AQS)详解一

    AQS在类的注释上说的已经很明白,提供一个框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量、事件等)。此类被设计做为大多数类型的同步器的一个有用的基础类,这些同步器依赖于单个原子int值(state字段)来表示状态。 java 并发编程系列文章

    2024年02月10日
    浏览(45)
  • Java并发编程第6讲——线程池(万字详解)

    Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池,本篇文章就详细介绍一下。 定义:线程池是一种用于管理和重用线程的技术(池化技术),它主要用于提高多线程应用程序的性能和效率。 ps:线程池、连接池、内存池

    2024年02月11日
    浏览(41)
  • 【并发编程】Java的Future机制详解(Future接口和FutureTask类)

    目录 一、彻底理解Java的Future模式 二、为什么出现Future机制 2.1 Future 类有什么用? 三、Future的相关类图 2.1 Future 接口 2.2 FutureTask 类 五、FutureTask源码分析 5.1 state字段 5.2 其他变量 5.3 CAS工具初始化 5.4 构造函数 5.5 jdk1.8和之前版本的区别 六、Callable 和 Future 有什么关系? 七、

    2024年02月03日
    浏览(39)
  • ElasticSearch 中的中文分词器以及索引基本操作详解,Java高并发编程详解深入理解pdf

    PUT book/_settings { “number_of_replicas”: 2 } 修改成功后,如下: 更新分片数也是一样。 2.3 修改索引的读写权限 索引创建成功后,可以向索引中写入文档: PUT book/_doc/1 { “title”:“三国演义” } 写入成功后,可以在 head 插件中查看: 默认情况下,索引是具备读写权限的,当然这

    2024年04月09日
    浏览(51)
  • Golang 并发编程详解

    并发是现代软件开发中的一个重要概念,它允许程序同时执行多个任务,提高系统的性能和响应能力。Golang 是一门天生支持并发的语言,它通过 goroutine 和 channel 提供了强大的并发编程支持。 在本文中,我们将深入探讨 Golang 中的并发编程,了解 goroutine、channel 以及一些常见

    2024年01月23日
    浏览(45)
  • 【并发编程篇】详解Forkjoin

    Fork/Join 是一种在多线程领域中常用的算法或技术, 它的核心思想是将大任务分割成若干个小任务,然后将这些小任务分配给多个线程并行处理,最终将结果合并起来 。这种思想可以应用于多种场景,例如图像处理、批处理、并行排序等。 在 Java 中,Fork/Join 这种思想被封装

    2024年01月17日
    浏览(76)
  • JUC并发编程之volatile详解

    目录   1. volatile 1.1 volatile的作用 1.1.1 变量可见性 1.1.2 禁止指令重排序 1.2 volatile可见性案例 1.3 volatile非原子性案例 1.4 volatile 禁止重排序 1.5 volatile 日常使用场景 送书活动   在并发编程中,多线程操作共享的变量时,可能会导致线程安全问题,如数据竞争、可见性

    2024年02月14日
    浏览(45)
  • Java并发编程:Semaphore

    信号量可以控制线程的并发数量 通常用于那些资源有明确访问数量限制的场景,常用于限流 。 使用 Semaphore 先调用 acquire() 获取,然后通过 try ... finally 保证在 finally 中释放。 Semaphore常用方法说明 acquire() 获取一个令牌,在获取到令牌、或者被其他线程调用中断之前线程一直

    2024年02月12日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包