BlockingQueue在任何时候都会对所有线程看起来一样吗?

时间:2014-01-14 10:10:47

标签: java multithreading locking queue

我正在实现一个程序,其中主线程将各种消息推送到工作线程,而工作线程将工作结果推回到主线程。

为此我计划使用两个队列,一个用于推送到工作线程,另一个用于从中拉出。

据我所知,线程缓存对象,因此如果它们是add()一个对象到另一个线程可以poll()的队列,则此更改可能不会立即显示,即它可能不会同步。这是对的吗?

但是,如果我使用BlockingQueue,那么该队列上的所有操作都应该立即对所有线程可见?

3 个答案:

答案 0 :(得分:1)

这个答案假设您正在讨论线程安全的数据结构或构造。如果您使用常规的非线程安全字段,则无法保证它将起作用,但也无法保证它不起作用。注意:这是线程安全有用的单元测试,但不是万无一失的。

  

此更改可能不会立即显示,即可能无法同步。这是对的吗?

是。延迟通常在50-100纳秒的数量级,因此几乎可以立即实现。

  

这个队列上的所有操作都应该立即对所有线程可见?

这在真机中是不可能的。您可以说的是,由于可见性问题,您应该永远不会收到错误,大多数都是非常轻微的延迟。 (但是,由于它会产生垃圾,因此在最坏的情况下可以获得全GC延迟,如果机器没有休眠,在这种情况下延迟可能是数小时或数天)

答案 1 :(得分:1)

BlockingQueue界面的javadoc说明了这一点:

  

BlockingQueue实现是线程安全的。所有排队方法都使用内部锁或其他形式的并发控制以原子方式实现它们的效果。”

因此,保证 1 在一个线程中对队列所做的更改对于其他线程“立即”...在内存模型意义上是可见的。我们会处理putpoll个来电的同步问题。 (任何缓存效果都由javadoc中提到的机制来处理。)

当然,这并不意味着所有人都会在语义层面看到变化。这取决于线程调度等事情。 (如果一个对象被添加到队列中,只有一个线程可以删除它。如果它在第二个线程看到队列状态之前执行此操作......无论出于何种原因......第二个线程将不会注意到添加然后删除了一个条目。)

“立即”的粒度也未指定。例如,如果JVM只使用一个CPU /核心,那么一个线程只能在发出poll调用的线程被解除调度后才能从put返回,无论出于何种原因。此外,刷新内存缓存中的更改需要花费大量时间。


1 - 这假设实现类符合“合同”......但如果不是,那就是错误。

答案 2 :(得分:1)

根据您的原始问题和评论,您会混淆两件不同的事情。

任何实现BlockingQueue的东西都是线程安全的并正确发布。实现该接口的类的内部结构各不相同,因此对于 immediate 的某些定义,声称“此队列上的所有操作应该立即对所有线程可见”的声明可能不正确。 “很快”将是一个更恰当的描述;它可能没有使用阻塞/锁定机制,并且总是涉及线程调度。

安全发布(线程缓存)与线程如何在Java中工作有关,并且是一个更大的主题。必须安全地发布对BlockingQueue的引用,以供所有线程查看。在大多数情况下,当使用这样的结构时,您可能正在做正确的事情。也就是说,要么将引用传递给Runnable构造函数,要么在某处将其创建为final变量。但实际上,只要你没有得到NullPointerException ......线程就可以看到它。

当您将传递给多个线程后,在中实例化对象之类的内容时,就会出现安全发布问题。

关于这个主题的事实上的参考是Java Concurrency in Practice,非常值得拥有。