同步队列 vs 交换器

16

Exchanger 和 SynchronousQueue 有什么区别?它们各自可以用于哪些场景?从性能角度来看,哪个更好?(锁方面呢?)


除非微秒很重要,否则使用哪个都无所谓。 - Peter Lawrey
2个回答

10
一个 Exchanger 更像是纯同步机制,而 SynchronousQueue 另外提供了标准队列数据结构的所有操作。这意味着您可以查看队列中有哪些对象,通过异步移除队列中的项目取消已计划但尚未执行的操作等 - 这些是 Exchanger 不提供的操作。由于许多实现允许设置队列大小的限制,因此您可以对资源使用进行附加控制,并且如果队列增长到某个特定阈值,则可以丢弃请求。另一方面,Exchanger 提供了两种方式的通信,而单个队列仅为单向(虽然可以手动实现在另一个方向上的通信)。由于许多实际情况只需要生产者和消费者之间的关系,因此队列通常更好,因为其 API 更易于理解,并且具有上述附加操作。

本文描述了Exchanger的一个实际使用案例。他们专注于在线程间通信时避免创建和垃圾回收新对象(具体实现取决于队列是否在添加内容时分配条目)。性能可能取决于您特定的用例。在示例中,他们使用Exchanger以提高效率(避免垃圾回收),但在大多数情况下(如果您不必提供亚毫秒级延迟),分配一个或两个对象并不是一个很大的问题,我更喜欢使用队列以获得额外的控制。

编辑:我查看了Oracle JDK中Exchanger.java的源代码,发现它确实在Exchanger.doExchange()中创建了Exchanger.Node类的临时对象。因此,与链接文章的作者所述相反,Exchanger并不是无分配的。显然,LinkedBlockingQueue也不是。相比之下,ArrayBlockingQueue在将项目附加到其中时不会分配任何临时对象。它只在创建时分配一个数组以容纳允许的最大元素数,但这只是一次性操作。在使用过程中,它不会创建新对象,因此从纯GC角度来看,它应该比Exchanger更好。


@Hemanshu 一个队列可能需要包装器,例如LinkedBlockingQueue需要Node对象,它们保存其有效负载以及对下一个链接项的引用。ArrayBlockingQueue不需要这样的包装器,但与LinkedBlockingQueue相比,它必须预先为其最大大小分配数组。这是一次性操作,通常没有问题,但是确实需要分配。因此,队列可能会导致每个项目额外的分配,但不一定需要。现在,我检查了Exchanger的代码,它实际上确实创建临时的Node对象。文章的作者似乎是完全错误的。 - Michał Kosmulski
@PeterLawrey 队列不会克隆存储在其中的对象,它只是传递引用,因此它也可以用于在线程之间传递相同的对象。Exchanger具有双向优势,所以我想这就是利润所在。但是,由于其内部工作原理,一些队列和Exchanger都会创建一些临时对象。 - Michał Kosmulski
Exchanger有一个优点,就是可以反复传递相同的两个对象。它不需要任何临时对象,因此避免了垃圾的产生。LinkedBlockingQueue每次等待时都会创建一个节点,并且它不能帮助您回收放置在队列中的对象。 - Peter Lawrey
3
我查看了Exchanger.java的源代码,发现在Exchanger.doExchange()方法中会创建Exchanger.Node类的临时对象。 - Michał Kosmulski
这是误导性的。SynchronousQueue并没有以有意义的方式实现任何类似队列的操作。 - undefined
显示剩余3条评论

3

让我们聚焦于重点...

  • Exchanger:是两个线程可以交换对象的约会点
  • SynchQueue:是一个队列!一个线程放入并等待,直到另一个线程弹出... 这里没有交换业务

Exchanger是一种双向的SyncQueue。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接