使用 Java 构造高可扩展应用,如何实现一个高效且多线程安全的队列

深入解析Java中的双向队列(Deque):操作、实现与应用 双向队列(Deque)凭借其两端操作的高效性,成为Java中解决复杂问题的利器。无论是实现栈、优化算法性能(如滑动窗口),还是设计高并发系统,双向队列都能提供简洁而强大的支持。开发者应根据具体场景选择ArrayDeque(性能优先)、LinkedList(功能多样)或并发实现类,充分发挥其灵活性和高效性。扩展思考如何用Deque实现一个线程安全的阻塞栈?探索Deque在图形搜索算法(如BFS的变种)中的应用。对比Deque与Queue在资源池管理中的优劣。 阅读详情

 

为什么性能没有增长?

多核能带来性能的大幅增长,这很容易通过简单的一些测试来观察到。如果我们写一个多线程程序,并在每个线程中对一个本地变量进行累加,我们可以很容易的看到多核和并行带来的成倍的性能提升。这非常容易做到,不是吗?在 参考资源 里我们给出了一个例子。然而,与我们的测试相反,我们很少在实际软件应用中看到这样完美的可扩展性。阻碍我们获得完美的可扩展性有两方面的因素存在。首先,我们面临着理论上的限制,其次软件开发过程中也经常出现实现上的问题。让我们看看 图 1 中的三条性能曲线:


图 1. 性能曲线
性能曲线

作为追求完美的软件工程师,我们希望看到随着线程数目的增长程序的性能获得线性的增长,也就是图 1 中的蓝色直线。而我们最不希望看到的是绿色的曲线,不管投入多少新的 CPU,性能也没有丝毫增长。(随着 CPU 增长而性能下降的曲线在实际项目中也存在)。而图中的红色线条则说明通常的 90-10 法则并不适用于可扩展性方面。假设程序中有 10% 的计算只能串行进行,那么其扩展性曲线如红线所示。由图可见,当 90% 的代码可以完美的并行时,在 10 个 CPU 存在的情况下,我们也只能获得大约 5 倍的性能。如果任务中具有无法并行的部分,那么在现实世界,我们的性能曲线大致上会位于图 1 中的灰色区域。

在这篇文章中,我们不会试图挑战理论极限。我们希望能解释一个 Java 程序员如何能够尽可能的接近极限,这已经不是一个容易的任务。

是什么造成了糟糕的可扩展性?

可扩展性糟糕的原因有很多,其中最为显著的是锁的滥用。这没有办法,我们就是这样被教育的:“想要多线程安全吗?那就加一个锁吧”。想想 Python 中臭名昭著的 Global Intepreter Lock,还有 Java 中的 Collections.synchronizedXXXX() 系列方法,跟随巨人的做法有什么不好吗?是的,用锁来保护关键区域非常方便,也较容易保证正确性,然而锁也意味着只有一个进程能进入关键区域,而其他的进程都在等待!如果观察到 CPU 空闲而软件执行缓慢,那么检察一下锁的使用是一个明智的做法。

对于 Java 程序而言,Performance Inspector 中的 Java Lock Monitor 是一个不错的开源工具。

对一个多线程应用进行调优

下面,我们将提供一个例子程序并演示如何在多核平台上获得更好的可扩展性。这个例子程序演示了一个假想的日志服务器。它接收来自多个源的日志信息并将其统一保存到文件系统中。为了简单起见,我们的例子代码中不包含任何的网络相关代码,Main() 函数将启动多个线程来发送日志信息到日志服务器中。对于性急的读者,让我们先看看调优的结果:


图 2. 日至服务器调优结果
日至服务器调优结果

在上图中,蓝色的曲线是一个基于 Lock 的老式日志服务器,而绿色的曲线是我们进行了性能调优之后的日志服务器。可以看到,LogServerBad 的性能随线程数目的增加变化很小,而 LogServerGood 的性能则随着线程数目的增加而线性增长。如果不介意使用第三方的库的话,那么来自 Project KunMing 的 LockFreeQueue 可以进一步提供更好的可扩展性:


图 3. 使用 Lock-free 的数据结构
使用 Lock-free 的数据结构

在上图中,第三条曲线表示用 LockFreeQueue 替换标准库中的 ConcurrentLinkedQueue 之后的性能曲线。可以看到,如果线程数目较少时,两条曲线差别不大,但是单线程数目增大到一定程度之后,Lock-Free 的数据结构具有明显的优势。

在下文中,将介绍在上述例子中使用的可以帮助我们创建高可扩展 Java 应用的工具和技巧。

使用 JLM 分析应用程序

JLM 提供了 Java 应用和 JVM 中锁持有时间和冲突统计。具体提供以下功能:

  • 对冲突的锁进行计数
    • 成功获得锁的次数
    • 递归锁的次数
    • 申请锁的线程被阻塞等待的次数
    • 锁被持有的累计时间。对于支持 3 Tier Spin Locking 的平台 , 还可以获得以下信息 :
      • 请求线程在内层(spin loop)请求锁的次数
      • 请求线程在外层(thread yield loop)请求锁的次数
  • 使用 rtdriver 工具收集更详细的信息
    • jlmlitestart:仅收集计数器
    • jlmstart:仅收集计数器和持有时间统计
    • jlmstop:停止数据收集
    • jlmdump:打印数据收集并继续收集过程
  • 从锁持有时间中去除垃圾收集(Garbage Collection,GC)的时间
    • GC 时间从 GC 周期中所有被持有的锁的持有时间中去除

使用 AtomicInteger 进行计数

通常,在我们实现多线程使用的计数器或随机数生成器时,会使用锁来保护共享变量。这样做的弊端是如果锁竞争的太厉害,会损害吞吐量,因为竞争的同步非常昂贵。

volatile 变量虽然可以使用比同步更低的成本存储共享变量,但它只可以保证其他线程能够立即看到对 volatile 变量的写入,无法保证读 - 修改 - 写的原子性。因此,volatile 变量无法用来实现正确的计数器和随机数生成器。

从 JDK 5 开始,java.util.concurrent.atomic 包中引入了原子变量,包括 AtomicInteger、AtomicLong、AtomicBoolean 以及数组 AtomicIntergerArray、AtomicLongArray 。原子变量保证了 ++,--,+=,-= 等操作的原子性。利用这些数据结构,您可以实现更高效的计数器和随机数生成器。

加入轻量级的线程池—— Executor

大多数并发应用程序是以执行任务(task)为基本单位进行管理的。通常情况下,我们会为每个任务单独创建一个线程来执行。这样会带来两个问题:一,大量的线程(>100)会消耗系统资源,使线程调度的开销变大,引起性能下降;二,对于生命周期短暂的任务,频繁地创建和消亡线程并不是明智的选择。因为创建和消亡线程的开销可能会大于使用多线程带来的性能好处。

一种更加合理的使用多线程的方法是使用线程池(Thread Pool)。 java.util.concurrent 提供了一个灵活的线程池实现:Executor 框架。这个框架可以用于异步任务执行,而且支持很多不同类型的任务执行策略。它还为任务提交和任务执行之间的解耦提供了标准的方法,为使用 Runnable 描述任务提供了通用的方式。 Executor 的实现还提供了对生命周期的支持和 hook 函数,可以添加如统计收集、应用程序管理机制和监视器等扩展。

在线程池中执行任务线程,可以重用已存在的线程,免除创建新的线程。这样可以在处理多个任务时减少线程创建、消亡的开销。同时,在任务到达时,工作线程通常已经存在,用于创建线程的等待时间不会延迟任务的执行,因此提高了响应性。通过适当的调整线程池的大小,在得到足够多的线程以保持处理器忙碌的同时,还可以防止过多的线程相互竞争资源,导致应用程序在线程管理上耗费过多的资源。

Executor 默认提供了一些有用的预设线程池,可以通过调用 Executors 的静态工厂方法来创建。

  • newFixedThreadPool:提供一个具有最大线程个数限制的线程池。
  • newCachedThreadPool:提供一个没有最大线程个数限制的线程池。
  • newSingleThreadExecutor:提供一个单线程的线程池。保证任务按照任务队列说规定的顺序(FIFO,LIFO,优先级)执行。
  • newScheduledThreadPool:提供一个具有最大线程个数限制线程池,并支持定时以及周期性的任务执行。

使用并发数据结构

Collection 框架曾为 Java 程序员带来了很多方便,但在多核时代,Collection 框架变得有些不大适应。多线程之间的共享数据总是存放在数据结构之中,如 Map、Stack、Queue、List、Set 等。 Collection 框架中的这些数据结构在默认情况下并不是多线程安全的,也就是说这些数据结构并不能安全地被多个线程同时访问。 JDK 通过提供 SynchronizedCollection 为这些类提供一层线程安全的接口,它是用 synchronized 关键字实现的,相当于为整个数据结构加上一把全局锁保证线程安全。

java.util.concurrent 中提供了更加高效 collection,如 ConcurrentHashMap/Set, ConcurrentLinkedQueue, ConcurrentSkipListMap/Set, CopyOnWriteArrayList/Set 。这些数据结构是为多线程并发访问而设计的,使用了细粒度的锁和新的 Lock-free 算法。除了在多线程条件下具有更高的性能,还提供了如 put-if-absent 这样适合并发应用的原子函数。

其他一些需要考虑的因素

不要给内存系统太大的压力

如果线程执行过程中需要分配内存,这在 Java 中通常不会造成问题。现代的 JVM 是高度优化的,它通常为每个线程保留一块 Buffer,这样在分配内存时,只要 buffer 没有用光,那么就不需要和全局的堆打交道。而本地 buffer 分配完毕之后 , JVM 将不得不到全局堆中分配内存,这样通常会带来严重的可扩展性的降低。另外,给 GC 带来的压力也会进一步降低程序的可扩展性。尽管我们有并行的 GC,但其可扩展性通常并不理想。如果一个循环执行的程序在每次执行中都需要分配临时对象,那么我们可以考虑利用 ThreadLocal 和 SoftReference 这样的技术来减少内存的分配。

使用 ThreadLocal

ThreadLocal 类能够被用来保存线程私有的状态信息,对于某些应用非常方便。通常来讲,它对可扩展性有正面的影响。它能为各个线程提供一个线程私有的变量,因而多个线程之间无须同步。需要注意的是在 JDK 1.6 之前,ThreadLocal 有着相当低效的实现,如果需要在 JDK 1.5 或更老的版本上使用 ThreadLocal,需要慎重评估其对性能的影响。类似的,目前 JDK 6 中的 ReentrantReadWriteLock 的实现也相当低效,如果想利用读锁之间不互斥的特性来提高可扩展性,同样需要进行 profile 来确认其适用程度。

锁的粒度很重要

粗粒度的全局锁在保证线程安全的同时,也会损害应用的性能。仔细考虑锁的粒度在构建高可扩展 Java 应用时非常重要。当 CPU 个数和线程数较少时,全局锁并不会引起激烈的竞争,因此获得一个锁的代价很小(JVM 对这种情况进行了优化)。随着 CPU 个数和线程数增多,对全局锁的竞争越来越激烈。除了一个获得锁的 CPU 可以继续工作外,其他试图获得该锁的 CPU 都只能闲置等待,导致整个系统的 CPU 利用率过低,系统性能不能得到充分利用。当我们遇到一个竞争激烈的全局锁时,可以尝试将锁划分为多个细粒度锁,每一个细粒度锁保护一部分共享资源。通过减小锁的粒度,可以降低该锁的竞争程度。 java.util.concurrent.ConcurrentHashMap 就通过使用细粒度锁,提高 HashMap 在多线程应用中的性能。在 ConcurrentHashMap 中,默认构造函数使用 16 个锁保护整个 Hash Map 。用户可以通过参数设定使用上千个锁,这样相当于将整个 Hash Map 划分为上千个碎片,每个碎片使用一个锁进行保护。

结论

通过选择一种合适的 profile 工具,检查 profile 结果中的热点区域。使用适合多线程访问的数据结构,线程池,细粒度锁减小热点区域。并重复此过程不断提高应用的可扩展性。

构建在多核上具有高可扩展性的 Java 应用并不是一件容易的事。减少各个线程之间的冲突和同步是提高可扩展性的关键。本文中介绍的一些通用工具和技巧可以给程序员提供一些帮助,但更多的情况要依赖于具体的应用。

 

 

使用 Java 实现一个简单且高效的任务调度框架 本文系统地介绍了如何使用 Java 设计与实现一个高吞吐、高可用、轻量级的任务调度框架。内容涵盖任务状态管理、线程池并发执行、阻塞队列解耦、失败重试机制及分布式扩展方案(如分片与 Redis 中心化调度)。通过逐步深入的架构演进与代码示例,帮助读者理解调度系统的核心设计原则与工程实现,为构建可扩展的任务处理平台提供实用参考。 阅读详情

相关推荐

Java环形队列的完整实现与应用

环形队列是一种使用固定大小的数组来模拟队列操作的数据结构。与传统的队列不同,环形队列的”尾部”会环绕回数组的”头部”,形成一个环状结构。这种结构让环形队列在处理循环缓冲区时特别有用,尤其是在资源有限且循环使用是必需的情况下。链表环形队列的核心是节点的设计,每个节点通常包含至少两个部分:存储数据的值和指向下一个节点的指针。在某些实现中,为了方便管理,还会添加一个指向前一个节点的指针。下面是一个简单的链表节点定义的示例代码:T data;// 数据域// 指向下一个节点的指针。

weixin_36299472的博客 796

java中使用多线程不能明显提高程序效率的一些原因

java中使用多线程不能明显提高程序效率的一些原因.   使用多个线程来处理多任务的时候,效率肯定是有提高的.但是必须要慎用,否则容易出现问题.   1,多线程主要是为了充分利用多核cpu,大内存这些资源. 如果你的硬件跟不上,只有一个cpu,那么多线程从并发变成了串行了,另外再加上线程上下文切换的时候,那你就得不偿失了. 2.原子问题 如果多线程是同步操作一个原子数据,(多个线程...

Coding First,Thinking Second 753

Java多线程与队列实现模拟排队叫号系统

Java中的线程概念是从操作系统层面抽象出来的,允许开发者通过简单的API来创建和控制线程。一个线程可以看作是程序中的一个执行流程,它拥有自己的调用栈和程序计数器。在Java中,任何对象都可以作为锁来控制对共享资源的访问,这是实现线程同步的基础。队列是一种先进先出(First In, First Out,FIFO)的数据结构,它允许最先进入队列的元素最先被取出。在多线程环境中,队列常被用作线程间的通信和协调机制,帮助管理任务的执行顺序和资源的分配。队列的核心操作包括:enqueue。

weixin_35797963的博客 924

多线程代码,性能怎么优化!

Java 中最烦人的,就是多线程,一不小心,代码写的比单线程还慢,这就让人非常尴尬。通常情况下,我们会使用 ThreadLocal 实现线程封闭,比如避免 SimpleDateFormat 在并发环境下所引起的一些不一致情况。其实还有一种解决方式。通过对parse方法进行加锁,也能保证日期处理类的正确运行,代码如图。

BASK2312的博客 409

线程安全型队列的实现

操作系统课程设计线程安全型队列,利用读者优先机制实现互斥。

关于深度可分离卷积

关于深度学习中的深度可分离卷积

qq_45670407的博客 1796

Java并发(二)----初次使用多线程并行提高效率

IO 操作不占用 cpu,只是我们一般拷贝文件使用的是【阻塞 IO】,这时相当于线程虽然不用 cpu,但需要一直等待 IO 结束,没能充分利用线程。但如果是四核 cpu,各个核心分别使用线程 1 执行计算 1,线程 2 执行计算 2,线程 3 执行计算 3,那么 3 个线程是并行的,花费时间只取决于最长的那个线程运行的时间,即。单核 cpu 下,多线程不能实际提高程序运行效率,只是为了能够在不同的任务之间切换,不同线程轮流使用 cpu ,不至于一个线程总占用 cpu,别的线程没法干活。

1216

5.1 滑模控制(SMC)及其改进

本文系统阐述了滑模控制(SMC)的基本原理及其在永磁同步电机(PMSM)控制系统中的应用。首先介绍了滑模控制的核心思想,包括滑模面设计和不连续控制律,其强鲁棒性使其在电机控制领域得到广泛应用。其次分析了SMC在PMSM速度控制器和无位置传感器观测器中的具体实现方案。重点探讨了SMC固有的抖振问题,详细比较了边界层法、高阶滑模和自适应方法等多种改进策略的优缺点。最后指出改进SMC的研究趋势是多种策略的融合应用,如自适应高阶滑模等,以在保持鲁棒性的同时有效抑制抖振。

技术工作者 1449

【已解决】利用 Java 多线程并发编程提高数据处理效率

需求很简单,只设计一般的联动数据库查询以及数据库的更新操作,然而在编码实现过程中发现,由于主机的数量很多,导致循环遍历查询、更新时花费很长的时间,调用一次接口大概需要30-40 min 时间才能完成操作。💡因此,为了有效缩短接口方法的执行时间,便考虑使用多线程并发编程方法,利用多核处理器并行执行的能力,通过异步处理数据的方式,便可以大大缩短执行时间,提高执行效率。🎉那么在使用多线程异步更新的策略后,从当初调用接口所需的大概时间为。📍这里使用可重用固定线程数的线程池。,大大提高了执行效率。

华仔仔的博客 7059

Edge浏览器IE模式失效?最新142版本隐藏按钮的3种解决方案

本文针对Edge浏览器142版本中IE模式按钮消失的问题,提供了3种实用解决方案,包括注册表修改、手动添加网站到IE模式列表和企业策略部署方案,帮助用户解决兼容性问题,确保老旧系统正常访问。

weixin_28308325的博客 501

使用 Restart Extension 继续解决 Ansys 机械分析

您正在执行复杂或大型的多步有限元分析,突然,您意识到经过数小时的求解后,您需要添加或修改边界条件。在本篇博文中,您将了解如何利用 Ansys Mechanical 中的 RestartAnalysis 扩展来扩展多步分析,方法是合并额外的时间步骤和边界条件,而不会丢失已计算的结果。幸运的是,在 Mechanical 中,有一种直接的方法可以实现这一点,而不会损害您之前的结果,而这在添加新边界条件和使用重新启动点时经常发生。得到的结果符合预期,您可以看到施加的力产生的这两个部分之间的相对位移。

jkh920184196的博客 1232

JVM-多线程高并发调优

多线程高并发调优

我是一只小小鸟,想要飞呀飞的更高。 901

STM32F103新手必看:0.96寸OLED屏幕从接线到动态显示全攻略(附IIC避坑指南)

本文为STM32F103新手提供了0.96寸OLED屏幕从硬件接线到软件驱动的完整实战指南。重点解析了IIC通信的时序、设备地址(0x78/0x7A)的常见陷阱,并详细演示了如何实现字符显示与平滑滚动显示等动态效果,帮助开发者快速上手并避开常见调试难题。

stone的博客 552

Java多线程总结之线程安全队列Queue

在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列。Java提供的线程安全的Queue可以分为阻塞队列和非阻塞队列,其中阻塞队列的典型例子是BlockingQueue,非阻塞队列的典型例子是ConcurrentLinkedQueue,在实际应用中要根据实际需要选用阻塞队列或者非阻塞队列。 注:什么叫线程安全?这个首先要明确。线程安全的类 ,指的是类内共享的全局变量的

bieleyang的博客 7万+

Jetson Nano摄像头选型与配置全攻略:CSI与USB接口实战指南

在嵌入式视觉与边缘计算项目中,摄像头作为核心传感器,其选型与配置直接影响系统性能。CSI(Camera Serial Interface)和USB(Universal Serial Bus)是两种主流接口,前者通过MIPI CSI-2协议直接与SoC通信,具备低延迟、高带宽特性,适合实时性要求高的应用;后者基于通用串行总线标准,即插即用,通用性强。在NVIDIA Jetson Nano平台上,合理选择摄像头接口并优化驱动配置,能充分发挥其GPU加速优势,提升图像处理流水线效率。本文聚焦Jetson Nano

weixin_29190651的博客 323

蓝牙协议栈详解(3)——BTstack

BTstack是一个轻量级蓝牙协议栈,支持经典蓝牙(BR/EDR)和低功耗蓝牙(BLE)。它采用事件驱动模型,可运行在MCU/CPU上,通过HCI接口与蓝牙控制器通信。协议栈包含完整的蓝牙协议层支持,如L2CAP、RFCOMM、ATT/GATT等,并提供丰富的示例代码。 主要特点包括模块化设计、开源授权、支持多种HCI传输方式(UART/USB)和操作系统适配。开发时需要关注事件驱动编程模型、内存配置优化、HCI传输稳定性等问题。典型应用场景包括SPP串口通信、BLE外设开发等。 使用建议从最小示例开始,逐

嵌入式软硬件叶玄 291

Java多线程实战-从零手搓一个简易线程池(一)定义任务等待队列

开个新坑-手搓简易线程池。本系列文章将从零开始,一步步手工编码实现一个简单但功能完备的线程池。我们将逐步介绍线程池的各个核心组件,并分析它们的作用和实现思路。通过这个过程,我们可以更好地掌握多线程编程的技巧,并培养编码能力和系统性思维。

qq_35716689的博客 25万+

【Unity3D框架】GameFramework框架完全教程《全网最全》-专栏文章目录

最近准备学习框架,了解到GameFramework框架是国产Unity3D框架,准备学习一下,但是奈何全网关于这个框架的教程实在太少。为了让自己学习方便一些,也为了让后来者乘凉。将框架以自己的理解整理目录,并且补全教程。觉得教程有帮助别忘了一键三连哦。

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2万+

阻塞队列的介绍和简单实现——多线程编程简单案例[多线程编程篇(4)]

在现代软件开发中,多线程编程能力已经成为程序员必须掌握的一项核心技能。随着计算机硬件的不断升级,单核CPU早已无法满足复杂应用的性能需求,多核并行运算已成为主流。而多线程正是实现资源最大化利用、任务高效并行执行的基础手段。而本博客是笔者多线程编程的第四篇博客!如何简单的去使用jconsloe 查看线程 (多线程编程篇1)_java jconsloe-优快云博客浅谈Thread类及常见方法与线程的状态(多线程编程篇2)_thread.join() 和thread.get()-优快云博客。

cjejwe的博客 3258

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

使用 Java 构造高可扩展应用

http://www.ibm.com/developerworks/cn/java/j-lo-scalbility/?S_TACT=105AGX52&S_CMP=tec-csdn#resources 使用 Java 构造高可扩展应用如何实现一个高效且多线程安全的队列文档选项

600

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

sqlite4java中的多线程队列使用(线程安全)

sqlite4java是sqlite驱动的一个开源项目,效率和稳定性非常的不错,关键是它在各个平台下均有本地实现,跨平台做的很不错,使用也非常的简单。该项目官方网站:https://code.google.com/p/sqlite4java/ 最新版本: sqlite4java-282 with SQLite 3.7.10 and Android support 但是关于其中多线程下确保

huxidong的专栏 3697

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

Java 8并发集合:安全高效的多线程集合

在多线程环境中,使用线程安全的数据结构非常重要,以避免竞态条件和数据不一致的问题。Java 8引入了一些并发集合类,提供了安全高效的多线程集合操作。本教程将介绍Java 8中的并发集合类,包括ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentSkipListSet和CopyOnWriteArrayList。

qq_38766930的博客 3872

Java多线程--队列(Queue)--使用/教程/实例

原文网址: 简介 本文用示例来介绍Java中的队列的用法。包括:DelayQueue,ConcurrentLinkedQueue,BlockingQueue。 文章最后有一个常见的面试题代码实例:机器要对手机按顺序做如下任务:生产、打包、发货。消费者等待收货,如何使用BlockingQueue完成? DelayQueue 简介 DelayQueue:只有当其指定的延迟时间到了,才能够从队列中获取到该元素。DelayQueue就是基于Priority...

IT利刃出鞘的博客 7366

JAVA多线程与队列

JAVA 已经给我们提供了比较好的队列实现Queue,继承于Collection。 本次我使用的是BlockingQueue,继承于Queue。 在

dearbaba_8520的博客 2368
上一篇: 编写更少的代码!使用 4 个 Apache Commons Lang 类了解代码重用的优点
下一篇: 自动检测并行 Java 程序中的错误
phantomhu
博客等级 码龄23年 70粉丝 24原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值