何时需要手动同步Java线程,何时不需要

3
在哪些情况下,您不必同步以传播数据从一个线程到另一个线程?

1
通常情况下,当一个线程执行的工作不会影响到其他线程所需的任何字段或对象时,您不需要对其进行同步处理。 - nbz
1
我感到很遗憾,有人投票关闭了这个问题。StackOverflow 真的走下坡路了。这是一个好的、真诚的、有建设性的问题。 - Jeff
1
同步有两个不同的原因:1)您不希望不同的线程同时执行某些代码块,2)您希望确保线程看到您的变量的相同最新值。您必须理解所有需要为这两个原因同步(或不同步)的情况,这可能非常微妙。 - toto2
5个回答

4

尝试使用Java同步教程。它将引导您了解基础知识。同时,请注意手动通过同步控制线程是缓慢和极易出错的。其他惯用语(和语言)已经发展,可以保护开发人员免受管理原始线程的复杂性。


3

有一些情况下,你不必同步线程以传播数据,因为JVM会隐式地为你执行同步操作。

这些情况包括:

  • 当数据由静态初始化器(静态字段或static{}块中的初始化器)初始化时
  • 访问final字段时
  • 在创建线程之前创建对象时
  • 当一个对象已经对一个它与之合并的线程可见时

3

如果您的应用程序只有一个线程(不包括垃圾收集线程,这是虚拟机的责任),则不需要使用同步。一些库(如Swing)引入了多线程,因此您需要注意。


避免线程同步的最简单方法是使用单线程模型。 - Steve Kuo

3
我理解你的问题是:“为什么不将所有方法标记为同步”,或者“为什么不自动将所有方法同步化”。
如果所有东西都被同步,你很可能无法从多线程中获得任何好处。虽然多个线程可以同时活动,但只有一个线程能够通过你的代码。
此外,同步会带来一定的开销,因为JVM会检查互斥锁。

1

如果您可以坚持使用一个线程,那么就不需要进行同步。如果您需要另一个线程,则将与该线程有关的所有内容同步是避免问题的简单方法。

但是,如果您有多个线程并希望从中获得最大利益,则希望尽一切可能避免同步。在这种情况下,您唯一需要同步的时间是当您拥有一组必须与彼此一致的字段,并且其中一个或多个字段可能会被另一个线程访问时。然后,您才需要同步块。

请注意,任何非线程安全类的对象都包含整个这样的字段集,并且即使在其自己上使用时也必须进行同步:

private final Collection  bigList;

synchronized (bigList)  {   // Protect bigList!
    bigList.add( something );
}

还有一种只有一个字段的情况,例如:

private final int  holderID;

if (holderID == 0)  {
    holderID = 2213;
    // Do other stuff thinking that holderID equals 2213 and no one else will try
    // to do the same other stuff, such as updating databases or writing to other
    // fields.
}

这确实需要同步。否则,如果您的CPU至少有10,000个核心,那么10,000个线程都可以同时执行此行(),看到holderID中的零,将该值设置为自己的数字,并造成严重后果。但是,自从1.5以来,您可以使用java.util.concurrent.atomic包来避免传统的、缓慢的同步。

在最小化同步多线程方面,您必须非常小心。仔细阅读,深思熟虑,并设计测试,使所有线程保持运行数分钟。使每个类和实例字段都不是最终易失性的。永远不要相信一个类或实例字段。尽快将所有值放入本地变量中,并尽可能长时间地保留它们。例如,不要这样做:

if (mainList != null)  mainList.get( 1 );

在两个引用之间,某些线程绑定到空的mainList。你可以同步它,但最好做:

MainList  ml = mainList;
if (ml != null)  ml = ml.get( 1 );

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