确保线程更新"对Java中的其他线程可读

时间:2015-03-05 02:14:23

标签: java multithreading caching

我有一个主线程将启动其他线程。那些其他线程将要求完成作业,主线程将使其他线程可以查看和执行作业。

必须完成的工作是将巨大的布尔数组中的索引设置为true。它们默认为false,其他线程只能将它们设置为true,永远不会为false。各种作业可能涉及将相同的索引设置为true。

主线程根据两件事找到新工作。

  1. 巨大布尔数组中的值。
  2. 已完成哪些工作。
  3. 如何确保主线程从巨大的布尔数组中读取新值?

    我无法通过同步方法更新数组,因为几乎所有其他线程都会这样做,因此我只会获得相当多的顺序性能。

    让我们说其他线程通过非同步函数将其中的许多索引设置为true来更新庞大的布尔数组。如何确保主线程读取更新并确保它不仅仅是在线程本地缓存?是否有任何方法可以实现"推动"更新?我猜测主线程应该只使用同步方法来获得"得到"更新?

4 个答案:

答案 0 :(得分:1)

对于您的问题的真正完整答案,您应该打开Java语言规范的副本,并在"之前搜索"。

当JLS说A"发生在" B,这意味着在Java语言的有效实现中,A需要在B之前实际发生。规范说明如下:

  • 如果某个线程更新某个字段,然后释放锁定(例如, 离开同步块),更新"发生在"锁是 释放,

  • 如果某个线程释放了一个锁,而另一个线程随后发布了 获得相同的锁,释放"发生在#34;收购。

  • 如果某个线程获取了一个锁,然后读取一个字段,那么 收购"发生在"阅读。

因为"发生在"之前是一个传递关系,你可以推断,如果线程A更新了一个synchronized块中的一些变量,然后线程B检查在同一个对象上同步的块中的变量,那么线程B将看到A写的线程。

除了进入和离开同步块之外,还有许多其他事件(构造对象,wait()ing / notify()对象,start()ing和join()线程,读取和写入volatile变量)允许你要建立"发生之前"线程之间的关系。

这不是您问题的快速解决方案,但本章值得一读。


  

...主线程将为其他线程提供工作以查看和执行...

     

我无法通过同步方法更新数组,因为几乎所有其他线程都是,并且......

听起来像你说的那样,每个工作线程只能在等待main()线程的进一步指令之前完成一些繁琐的工作。如果这是真的,那么大多数工人大部分时间都会等待。如果您只是在一个线程中完成所有工作,那么您可能会获得更好的性能。

假设您的目标是充分利用多处理器计算机的可用周期,您需要以某种方式对工作进行分区,以便在需要同步之前让每个工作线程都关闭并执行大量工作与任何其他线程。

答案 1 :(得分:0)

我会使用另一种设计模式。例如,您可以在设置布尔值的索引时添加它们,例如,然后同步对该布局值的访问。然后你可以使用wait / notify来唤醒。

答案 2 :(得分:0)

首先,一般不要使用布尔数组,请使用BitSet。请参阅:boolean[] vs. BitSet: Which is more efficient?

在这种情况下,您需要一个原子BitSet,因此您不能使用java.util.BitSet,但这里有一个:AtomicBitSet implementation for java

答案 3 :(得分:0)

您可以将此模型化为消息传递而不是改变共享状态。在您的描述中,worker从不读取布尔数组,只写完成状态。您是否考虑过使用工作人员使用的待处理作业队列以及主控读取的完成队列?主线程可以有效地维护作业状态字段,而不需要任何共享状态问题。根据您的需要,您可以使用阻塞或非阻塞队列。