基本的Java线程问题

时间:2009-12-03 18:45:06

标签: java optimization java-me thread-safety

让我说我正在与一个有两个相互依赖的递增计数器的系统进行交互(这些计数器永远不会递减): int totalFoos; // barredFoos加上nonBarredFoos int barredFoos;

我也有两种方法: int getTotalFoos(); //基本上是对localhost的网络调用 int getBarredFoos(); //基本上是对localhost的网络调用

这两个计数器由我无法访问的代码保存和增加。假设它在一个备用线程上递增两个计数器,但是以线程安全的方式递增(即在任何给定的时间点,两个计数器将同步)。

在单个时间点准确计算barredFoos和nonBarredFoos的最佳方法是什么?

完全天真的实施:

int totalFoos = getTotalFoos();
int barredFoos = getBarredFoos();
int nonBarredFoos = totalFoos - barredFoos;

这有一个问题,系统可能会在两个方法调用之间增加两个计数器,然后我的两个副本将不同步,barredFoos的值将超过{{1}时的值被抓了。

基本的双重检查实施:

totalFoos

这应该在理论上有效,但是我不确定JVM是否保证这是在实践中实际发生的事情,一旦优化并考虑到这一点。有关这些问题的示例,请参阅http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html(通过Romain Muller链接)。

鉴于我拥有的方法和上面的假设,计数器实际上是一起更新的,有没有办法可以保证我的两个计数副本是同步的?

6 个答案:

答案 0 :(得分:3)

是的,我相信你的实施就足够了;真正的工作是确保getTotalFoosgetBarredFoos返回的值确实同步并始终返回最新值。但是,正如你所说,情况已经如此。

当然,使用此代码可以运行的一件事是无限循环;你想要确保在如此短的时间内改变这两个值将是一个非常特殊的情况,即便如此我认为建立一个安全(即最大迭代次数)以避免获得肯定是明智的陷入无尽的循环。如果来自这些计数器的值是您无法访问的代码,那么您不希望完全依赖于事情永远不会在另一端出错。

答案 1 :(得分:1)

为了保证跨线程的读取性能 - 并防止代码执行重新排序,尤其是在多核机器上,您需要同步对这些变量的所有读写访问。此外,为了确保在单个线程上您可以看到当前计算中使用的所有变量的最新值,您需要在读取访问时进行同步。

更新:我错过了关于通过网络获取两个变量的值的单独调用的调用 - 这使得双重检查锁定问题(因此没有api方法可用于如果您同时返回两个值,则无法绝对保证两个变量在任何时间点的一致性。

请参阅Brian Goetz关于Java memory model的文章。

答案 2 :(得分:0)

你可能可能不能可靠地做你想要的事情,除非你正在与之交互的系统有一个方法,你可以一次检索这两个值(以原子方式)。

答案 3 :(得分:0)

我也会提到AtomicInteger,但这不起作用,因为

1)你有两个整数,而不仅仅是一个整数。 AtomicIntegers不会帮助你。 2)他无权访问底层代码。

我的问题是,即使您无法修改基础代码,您可以控制 执行时吗?您可以在修改这些计数器的任何函数周围放置同步块。这可能不太令人愉快,(它可能比你的循环慢),但这可能是“正确”的做法。

如果你甚至无法控制内部线程,那么我猜你的循环会起作用。

最后,如果您确实控制了代码,那么最好的方法是让一个同步函数在运行时阻止对两个整数的访问,并在int []中返回它们中的两个。

答案 4 :(得分:0)

鉴于没有办法访问维持不变“totalFoos = barredFoos + nonBarredFoos”的任何锁定机制,因此无法确保您检索的值与该不变量一致。遗憾。

答案 5 :(得分:-1)

包含代码的方法

while (true) {    
 int totalFoos = getTotalFoos();    
 int barredFoos = getBarredFoos();    
 if (totalFoos == getTotalFoos()) {        
  int nonBarredFoos = totalFoos - barredFoos;        
  break;    
 } 

}

应该同步

private synchronized void getFoos()