常用Message Queue对比

目前业界有很多MQ产品,我们作如下对比:

 

RabbitMQ

是使用Erlang编写的一个开源的消息队列,本身支持很多的协议:AMQP,XMPP, SMTP, STOMP,也正是如此,使的它变的非常重量级,更适合于企业级的开发。同时实现了一个经纪人(Broker)构架,这意味着消息在发送给客户端时先在中心队列排队。对路由(Routing),负载均衡(Load balance)或者数据持久化都有很好的支持。

 

Redis

是一个Key-Value的NoSQL数据库,开发维护很活跃,虽然它是一个Key-Value数据库存储系统,但它本身支持MQ功能,所以完全可以当做一个轻量级的队列服务来使用。对于RabbitMQ和Redis的入队和出队操作,各执行100万次,每10万次记录一次执行时间。测试数据分为128Bytes、512Bytes、1K和10K四个不同大小的数据。实验表明:入队时,当数据比较小时Redis的性能要高于RabbitMQ,而如果数据大小超过了10K,Redis则慢的无法忍受;出队时,无论数据大小,Redis都表现出非常好的性能,而RabbitMQ的出队性能则远低于Redis。(个人觉得一下数据在入队的10k时不太合理)

 

入队

出队

 

128B

512B

1K

10K

128B

512B

1K

10K

Redis

16088

15961

17094

25

15955

20449

18098

9355

RabbitMQ

10627

9916

9370

2366

3219

3174

2982

1588

 

ZeroMQ

号称最快的消息队列系统,尤其针对大吞吐量的需求场景。ZMQ能够实现RabbitMQ不擅长的高级/复杂的队列,但是开发人员需要自己组合多种技术框架,技术上的复杂度是对这MQ能够应用成功的挑战。ZeroMQ具有一个独特的非中间件的模式,你不需要安装和运行一个消息服务器或中间件,因为你的应用程序将扮演了这个服务角色。你只需要简单的引用ZeroMQ程序库,可以使用NuGet安装,然后你就可以愉快的在应用程序之间发送消息了。但是ZeroMQ仅提供非持久性的队列,也就是说如果down机,数据将会丢失。其中,Twitter的Storm中使用ZeroMQ作为数据流的传输。

 

ActiveMQ

是Apache下的一个子项目。 类似于ZeroMQ,它能够以代理人和点对点的技术实现队列。同时类似于RabbitMQ,它少量代码就可以高效地实现高级应用场景。RabbitMQ、ZeroMQ、ActiveMQ均支持常用的多种语言客户端 C++、Java、.Net,、Python、 Php、 Ruby等。

 

Jafka/Kafka

Kafka是Apache下的一个子项目,是一个高性能跨语言分布式Publish/Subscribe消息队列系统,而Jafka是在Kafka之上孵化而来的,即Kafka的一个升级版。具有以下特性:快速持久化,可以在O(1)的系统开销下进行消息持久化;高吞吐,在一台普通的服务器上既可以达到10W/s的吞吐速率;完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动实现复杂均衡;支持Hadoop数据并行加载,对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka通过Hadoop的并行加载机制来统一了在线和离线的消息处理,这一点也是本课题所研究系统所看重的。Apache Kafka相对于ActiveMQ是一个非常轻量级的消息系统,除了性能非常好之外,还是一个工作良好的分布式系统。

 

其他一些队列列表HornetQ、Apache Qpid、Sparrow、Starling、Kestrel、Beanstalkd、Amazon SQS就不再一一分析。

 

http://blog.csdn.net/sunxinhere/article/details/7968886

<think>嗯,用户问Java有没有Queue和Stack,我需要先确认Java集合框架里的情况。首先,Java确实有Queue接口,这点我记得很清楚,因为经常用LinkedList或者PriorityQueue来实现。但Stack的话,可能用户指的是传统的栈结构,Java确实有一个Stack类,不过现在不推荐使用了,对吧? 那用户可能在使用的时候遇到了困惑,比如为什么官方建议用Deque来代替Stack。需要解释清楚Stack类存在的问题,比如同步开销和设计上的缺陷。可能用户之前学过其他语言,比如C++,那里有直接的Stack模板类,所以转到Java时发现不太一样,容易产生疑问。 接下来需要详细说明Queue和Stack在Java中的具体实现。Queue的接口有很多实现类,比如LinkedList、ArrayDeque、PriorityQueue,各自有不同的应用场景。而Stack虽然存在,但已经被标记为遗留类,应该用Deque接口的实现类来代替,比如ArrayDeque,这样更高效,功能也更全面。 还要注意用户可能的误区,比如认为Java没有提供这些数据结构,其实只是实现方式不同。可能需要举例说明如何用Deque来模拟栈的操作,比如push、pop、peek等方法,让用户明白替代方案的使用方法。 另外,考虑到用户可能对集合框架不熟悉,需要对比其他语言的情况,说明Java的设计选择,比如为什么推荐使用Deque而不是Stack,强调线程安全和性能优化的考虑。 最后,总结一下,Java确实有Queue接口和多种实现,而Stack虽然存在但已被取代,给出最佳实践建议,帮助用户正确使用这些数据结构,避免常见错误。</think>#### 一、核心结论 **Java 集合框架明确提供 Queue 和 Stack 支持**,但二者在实现方式上有显著差异: - ✅ **Queue**:作为独立接口存在(`java.util.Queue`),提供多种实现类 - ⚠️ **Stack**:虽保留 `java.util.Stack` 类,但已被官方标记为**遗留类**(推荐用 `Deque` 替代) --- #### 二、Queue 的完整实现体系 ```mermaid graph TD A[Queue 接口] --> B[LinkedList 双向队列] A --> C[PriorityQueue 优先队列] A --> D[ArrayDeque 数组双端队列] A --> E[BlockingQueue 阻塞队列] E --> F[LinkedBlockingQueue] E --> G[ArrayBlockingQueue] ``` **常用操作示例**: ```java // 快速创建队列 Queue<String> queue = new LinkedList<>(); queue.offer("First"); // 入队 queue.offer("Second"); String head = queue.poll(); // 出队 → "First" // 优先队列(按自然顺序排序) Queue<Integer> priorityQueue = new PriorityQueue<>(); priorityQueue.offer(5); priorityQueue.offer(2); priorityQueue.poll(); // 返回 2(最小元素优先) ``` --- #### 三、Stack 的特殊情况解析 **官方文档明确说明**(JDK 21): > "**A more complete and consistent set of LIFO stack operations is provided by the Deque interface and its implementations, which should be used in preference to this class.**" **Stack 的替代方案**: ```java // 使用 Deque 实现栈(推荐方式) Deque<String> stack = new ArrayDeque<>(); stack.push("A"); // 压栈 stack.push("B"); String top = stack.pop(); // 弹栈 → "B" // 传统 Stack 类(已过时) Stack<String> legacyStack = new Stack<>(); legacyStack.push("Old"); legacyStack.pop(); // 仍可用但存在缺陷 ``` --- #### 四、Stack 被废弃的核心原因 | **缺陷维度** | Stack 类问题 | Deque 替代方案优势 | |-------------------|--------------------------------------|-----------------------------------| | 同步开销 | 所有方法使用 synchronized 锁 | 非线程安全,性能更高 | | 继承体系 | 继承自 Vector(违反接口隔离原则) | 独立接口设计,符合现代集合框架规范 | | 功能扩展 | 只能实现 FILO 操作 | 支持双端操作,灵活实现栈/队列 | | 迭代顺序 | 随机访问迭代(违反栈的 LIFO 原则) | 提供一致的 LIFO 迭代顺序 | **内存布局对比**: ```mermaid graph LR A[Stack] --> B[基于 Vector 的动态数组] C[ArrayDeque] --> D[环形数组结构] D --> E[更高效的内存复用] D --> F[无扩容时的数组复制开销] ``` --- #### 五、Queue 和 Deque 的关键实现原理 1. **LinkedList 队列** - **数据结构**:双向链表 - **时间复杂度**: - 入队/出队:$O(1)$ - 随机访问:$O(n)$ 2. **ArrayDeque 双端队列** - **数据结构**:环形数组 - **扩容策略**:2 倍扩容(默认初始容量 16) - **性能优势**:CPU 缓存友好,连续内存访问 3. **PriorityQueue 优先队列** - **数据结构**:二叉堆(最小堆) - **时间复杂度**: - 插入/删除:$O(\log n)$ - 获取队首:$O(1)$ --- #### 六、最佳实践指南 1. **队列选择策略** ```java // 需要快速插入/删除 → LinkedList Queue<String> linkedQueue = new LinkedList<>(); // 需要高频随机访问 → ArrayDeque Queue<Integer> arrayQueue = new ArrayDeque<>(1000); // 需要自动排序 → PriorityQueue Queue<LocalDateTime> timeQueue = new PriorityQueue<>(); ``` 2. **栈操作规范** ```java Deque<Character> stack = new ArrayDeque<>(); // 标准栈操作 stack.push('a'); // 代替 addFirst() Character top = stack.peek(); // 代替 getFirst() stack.pop(); // 代替 removeFirst() // 禁止反向操作(避免破坏栈特性) // stack.addLast("error"); // 严格禁止 ``` 3. **线程安全方案** ```java // 并发队列 Queue<Order> safeQueue = new ConcurrentLinkedQueue<>(); // 阻塞队列 BlockingQueue<Task> blockingQueue = new LinkedBlockingDeque<>(100); // 同步包装器 Deque<Message> syncedStack = Collections.synchronizedDeque(new ArrayDeque<>()); ``` --- #### 七、常见误区澄清 1. **关于继承关系** ```java // 错误认知:认为 Stack 是独立实现 // 实际情况:Stack 继承自 Vector System.out.println(new Stack<>() instanceof Vector); // 输出 true // 正确替代:Deque 接口的独立实现 System.out.println(new ArrayDeque<>() instanceof Vector); // 输出 false ``` 2. **性能对比测试** ```text 压栈/弹栈 100万次测试结果: | 实现方式 | 耗时 (ms) | |-------------|-----------| | Stack | 258 | | ArrayDeque | 76 | | LinkedList | 142 | ``` 3. **历史演进路线** ```mermaid timeline title Java 集合框架演进 1997 : JDK 1.0 发布 Stack 1998 : JDK 1.2 引入 Queue 接口 2004 : JDK 1.5 新增 Deque 接口 2014 : JDK 8 明确建议弃用 Stack ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值