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

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

如果您的方法仅对参数和本地定义(而不是类成员)变量进行操作,则需要担心零同步问题。

但…

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

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对象的引用,并在您仍然在方法或工作集的方法中执行操作时将其传递给另一个线程。 在这里你必须更加防守。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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