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

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

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作为任务的队列,随后在很多开源项目中都发现了内存泄漏的问题

在多核CPU编程中,TBB并发容器如concurrent_queue、concurrent_vector和concurrent_hash_map等提供了线程安全的数据结构,极大地简化了并发编程的复杂性,并能够有效提高程序的并发性能。这些容器通过内部优化减少了锁的使用,从而减少了线程之间的竞争,允许并发访问而无需开发者手动进行同步操作。 参考资源链接:[Intel TBB并发容器实战:concurrent_queue, concurrent_vector, concurrent_hash_map](https://wenku.youkuaiyun.com/doc/64a7fdf12d07955edb4d4381?spm=1055.2569.3001.10343) concurrent_queue是专为生产者-消费者模式设计的线程安全队列。它允许多个生产者线程并发地向队列中添加元素,同时多个消费者线程也可以并发地从队列中取出元素。由于内部机制保证了操作的原子性,开发者无需担心数据的竞争和不一致性。 concurrent_vector提供了一个线程安全的动态数组,可以在多个线程中安全地进行插入和删除操作。它的内部机制动态地管理内存分配和元素的移动,确保并发访问时的数据安全。 concurrent_hash_map是一个线程安全的哈希表,允许多个线程并发地访问和修改映射。它采用了细粒度的锁机制,减少了锁争用,提高了并发访问的性能。 以下是使用这些并发容器的代码示例: ```cpp #include <tbb/concurrent_queue.h> #include <tbb/concurrent_vector.h> #include <tbb/concurrent_hash_map.h> #include <thread> // 使用 concurrent_queue 示例 tbb::concurrent_queue<int> q; void producer() { for (int i = 0; i < 100; ++i) { q.push(i); } } void consumer() { int item; while (q.try_pop(item)) { std::cout << item << std::endl; } } // 使用 concurrent_vector 示例 tbb::concurrent_vector<int> v; void push_values() { for (int i = 0; i < 100; ++i) { v.push_back(i); } } void print_values() { for (auto& val : v) { std::cout << val << std::endl; } } // 使用 concurrent_hash_map 示例 tbb::concurrent_hash_map<int, std::string> hm; void store_values() { for (int i = 0; i < 100; ++i) { hm[i] = std::to_string(i); } } void retrieve_values() { for (auto& [key, value] : hm) { std::cout << key << 参考资源链接:[Intel TBB并发容器实战:concurrent_queue, concurrent_vector, concurrent_hash_map](https://wenku.youkuaiyun.com/doc/64a7fdf12d07955edb4d4381?spm=1055.2569.3001.10343)
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值