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

时间:2011-07-14 15:26:19

标签: java multithreading

在什么情况下,您不必同步将数据从一个线程传播到另一个线程?

5 个答案:

答案 0 :(得分:4)

试试Java Synchronization tutorial。它将引导您完成基础知识。还要意识到通过同步手动控制线程很慢并且极易出错。其他成语(和语言)已经发展,使开发人员免于管理原始线程的复杂性。

答案 1 :(得分:3)

在某些情况下,您不必同步将数据从一个线程传播到另一个线程,因为JVM 隐式为您执行同步。

这些案例包括:

  • 当数据由静态初始化程序(静态字段或静态{}块中的初始值设定项)初始化时
  • 访问最终字段时
  • 在创建线程之前创建对象时
  • 当一个对象已经被一个线程看到,然后它与
  • 连接

答案 2 :(得分:3)

如果您的应用程序只有一个线程(不计入垃圾收集线程,这是VM的职责),则不需要使用同步。一些库,如Swing,引入了多线程,所以你必须要注意。

答案 3 :(得分:3)

我的问题是:“为什么不将所有方法标记为同步”或“为什么并非所有方法都自动同步”

如果所有内容都已同步,您可能无法从多线程中获益。多个线程可以处于活动状态,但一次只能有一个线程可以通过您的代码。

此外,同步会产生开销,这可能很大,因为JVM会检查互斥锁。

答案 4 :(得分: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.
}

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

您必须非常小心最低限度同步的多线程。阅读,思考并设计测试,让所有线程一次只能运行几分钟。使每个类和实例字段不是最终的volatile。永远不要相信类或实例字段。尽快将所有值都放入局部变量中,并尽可能长时间保存在局部变量中。例如,不要这样做:

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

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

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