在Java中,是否需要同步不使用静态或类变量的方法?

时间:2011-01-22 04:32:07

标签: java multithreading static synchronization local

仅使用局部变量的方法是否会遇到任何线程问题?在某处提到过,使用局部变量的方法被复制到每个线程堆栈框架中,并且不需要为多线程实现进行同步,除非它使用类级别或静态引用/变量?

4 个答案:

答案 0 :(得分:8)

如果你的方法只对参数和本地定义的(而不是类成员)变量进行操作,那么就不用担心会出现零同步问题。

但是...

这意味着您使用的任何可变引用类型必须在您的方法范围内仅生存 。 (不可变的引用类型在这里不是问题。)例如,这没有问题:

int doSomething(int myParameter)
{
  MyObject working_set = new MyObject();
  interim = working_set.doSomethingElse(myParameter);
  return working_set.doSomethingElseAgain(interim);
}

在你的方法中创建一个MyObject实例,它的所有工作都在你的方法中工作并咳血,等待你退出方法时被GC剔除。

另一方面,这可能是一个问题:

int doSomething(int myParameter)
{
  MyObject working_set = new MyObject();
  interim = working_set.doSomethingElse(myParameter);
  another_interim = doSomethingSneaky(working_set);
  return working_set.doSomethingElseAgain(another_interim);
}

除非您确切知道doSomethingSneaky()中发生了什么,否则您可能需要在某处进行同步。具体而言,您可能必须对working_set上的操作进行同步,因为doSomethingSneaky()可能存储对本地working_set对象的引用,并在您仍在执行某些操作时将其传递给另一个线程在您的方法或working_set的方法中。在这里,你必须更加防守。

当然,如果你只使用原始类型,甚至调用其他方法,传递这些值,也不会有问题。

答案 1 :(得分:4)

  

仅在内部使用局部变量的方法是否会遇到任何线程问题?

在非常简单的意义上是真实的,但我们要清楚 - 我认为只有在以下情况下才会这样:

  • 这样的方法只使用作为基元的局部变量或对可变实例的引用,否则无法通过任何其他方式在方法外部访问。

  • 这样的方法只调用线程安全的方法。

可能违反这些规则的一些方法:

  • 可以初始化局部变量以指向也可以在方法外部访问的对象。例如,局部变量可以指向单例(Foo bar = Foo.getSingleton())。

  • 如果将实例作为参数传递给保留对实例的引用的外部方法,则局部变量持有的本地实例可能会“泄漏”。

  • 没有实例变量且只有一个没有局部变量的方法的类仍然可以调用另一个非线程安全的类的静态方法。

答案 2 :(得分:1)

这个问题非常通用,所以请不要指望我的回答有任何特殊性。

1_我们需要更加小心静态方法而不是实例方法。

2_ @Justmycorrectopinion是正确的,但他所描述的一些术语需要更加精细化才能完美。 (即使静态方法只适用于局部变量,仍然存在竞争条件的可能性。)

3_对我来说,有一些简单的规则可以帮助我分析线程安全性。

了解封装在其中的每个组件是否可共享。所以最简单的解决方案是减少所有变量的范围,只有在绝对必要时才增加范围,如果组件在对象上执行变异,它通常不是线程安全的。

4_使用工具支持对线程安全性执行静态代码分析。 (Idea有checkthread插件)。

5_永远不要使用静态方法来执行对象变异。如果调用静态变量导致对象变异,那么开发人员只是绕过OOPS。

6_始终记录线程安全。记住,开发时可能不需要同步某些方法,但可以很容易地使其不是线程安全的。

7_最后但可能是我最重要的一点,确保你的大部分对象都是不可变的。根据我的经验,大多数时候,我从来没有让我的许多物品变得可变。 (在极少数情况下,当需要更改对象状态时,防御性复制/新对象创建几乎总是更好。)

答案 3 :(得分:0)

您无需担心局部变量。然而,实例变量值得关注。