并发容器:ConcurrentQueue(并发队列)简单介绍

本文介绍了Java中无锁并发队列ConcurrentLinkedQueue和ConcurrentLinkedDeque,它们在高并发环境下提供高效、线程安全的解决方案。然而,使用size()方法可能造成效率低下且返回值不准确。此外,ConcurrentLinkedQueue在执行remove操作时可能存在性能下降和内存泄漏问题,这一问题在某些开源项目中被发现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 介绍

在Java中有没有一种队列的实现方式可以不用关心临界值的判断,操作该队列的线程也不会被挂起并且等待被其他线程唤醒,我们只是单纯地向该队列中插入或者获取数据,并且该队列是线程安全的,是可以应用于高并发多线程的场景中呢?在JDK1.5版本以前要实现这些要求我们大致有两种方式,具体如下:

  • 通过synchronized关键字对非线程安全的队列或者链表的操作方法进行同步。
  • 使用Collections类的同步方法

但是synchronized关键字相对于显式锁Lock甚至无锁的实现方式来说效率低下,因此自JDK1.5版本后,Java的开发者们实现了无锁的且线程安全的并发队列实现方案,开发者可以直接借助于它们开发出高性能的应用程序

  • ConcurrentLinkedQueue:无锁的、线程安全的、性能高效的、基于链表结构实现的FIFO单向队列(在JDK1.5版本中被引入)
  • ConcurrentLinkedDeque:无锁的、线程安全的、性能高效的、基于链表结构实现的双向队列(在JDK1.7版本中被引入)。

ConcurrentLinkedQueue和ConcurrentLinkedDeque的使用都是比较简单的,就不做过多介绍

2 并发队列在使用中需要注意的问题

  1. 在并发队列中使用size方法不是个好主意
    我们知道每一个Collection(队列Queue也是Collection的子接口)都提供了size()方法用于获取Collection中的元素个数,但是在并发队列中执行该方法却不是一个明智的操作:

    • 首先,并发队列是基于链表的结构实现的,并且在其内部并未提供类似于计数器的变量(当元素插入队列计数器时增一,当元素从队列头部被移除时计数器减一),因此想要获得当前队列的元素个数,需要遍历整个队列才能计算得出(效率低下)。
    • 其次并发队列采用无锁(Lock-Free)的算法实现,因此在某个线程中执行size()方法获取元素数量的同时,其他线程也可以对该队列进行读写操作,所以size()返回的数值不会是一个精确值,而是一个近似值、一个估计值。
  2. ConcurrentLinkedQueue的内存泄漏问题
    ConcurrentLinkedQueue在执行remove方法删除元素时还会出现性能越来越低,甚至内存泄漏的问题。这个问题最早是由Jetty的开发者发现的,因为Jetty内部的线程池采用的就是ConcurrentLinkedQueue作为任务的队列,随后在很多开源项目中都发现了内存泄漏的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值