【问题标题】:Does "local variables are thread safe" come with a condition?“局部变量是线程安全的”是否带有条件?
【发布时间】:2017-11-12 14:33:53
【问题描述】:

在另一个帖子中我遇到了这个问题,所以我必须把它作为一个简单而集中的问题放在这里。

void method(){

   Machine machine = new Machine();
   ...
}

class Machine{
   private static Tool tool = new Tool();    
   ...
}

虽然 Machine 是 method() 中的局部变量,但它仍然是线程不安全的,因为 Machine 有一个静态实例变量“tool”,它可能是潜在的线程不安全的,因为所有线程都将共享这个“工具”对象,因为它是静态的。

因此,如果 Machine 通过任何方式本身都是线程安全的,那么可以安全地声明“局部变量机器”是线程安全的。否则,即使 'machine' 是局部变量,它也不安全。

这种理解正确吗?

【问题讨论】:

  • “虽然 Machine 是方法中的局部变量” - 它不是,它是一个类,是 Class 类型的对象,并且驻留在堆中的某个位置。 “machine”确实是一个局部变量,但它只包含对使用表达式“new Machine()”创建的 Machine 类型对象的引用,而对象本身又像任何其他对象一样位于堆中。

标签: java multithreading


【解决方案1】:

是的,这个理解是正确的。只有变量本身是线程安全的,也就是说其他线程不会同时修改它的值。

这种保护不会扩展到局部变量引用的对象:根据对象的内部构造,例如可变性和静态变量的使用,对象可能是线程安全的,也可能不是线程安全的。

请注意,原始类型的局部变量和引用不可变对象的局部变量始终是线程安全的。

【讨论】:

  • 所以在我看来,“局部变量是线程安全的”的说法没有多大意义,因为很多时候你仍然必须确保在方法中创建的本地对象是线程安全的。这与其他变量没有太大区别。
  • @user697911 这是有道理的,因为如果您将某些内容放在局部变量中,您不必考虑同步访问它,因为其他线程无论如何都无法访问它。如果您将某些内容放入实例变量中,则必须考虑并发环境中的同步。除了考虑变量引用的类的内容之外,这仍然是局部变量和实例变量的关注点。
  • @dasblinklight's:在这个例子中,使静态变量线程安全的常用方法是什么?
  • @martin 如果可以的话,让它成为final;如果必须写入,请使用同步方法或显式锁定。
  • @user697911,声称“局部变量是线程安全的”是绝对正确的。它们是线程安全的,因为一个 Java 线程不可能访问不同线程的局部变量。如果您发现该声明完全令人困惑、误导或不满意,那么这可能意味着您仍然没有完全理解“局部变量”的含义。
【解决方案2】:

是的,语句局部变量是线程安全的带有几个条件。

首先,让我们看看为什么局部变量是线程安全的。这是因为变量分配在方法自己的堆栈帧上,不与任何其他执行路径共享。

因此,重要的是要注意变量本身是线程安全的,不一定是它所指向的。换句话说:

  • 原始变量是完全线程安全的,因为值本身就在堆栈中
  • 对象引用是一个更复杂的故事,因为实际对象是在堆上创建的,而堆栈帧只是指向堆内存。

在下图中,整数变量是线程安全的,但 Object 和 Array 不是。

对象是否是线程安全的完全取决于类是否被设计为线程安全的。

【讨论】:

  • 我也对这个问题感兴趣。那么使机器或工具线程安全的通常方法是什么,以便在这种情况下方法()是安全的?
  • martin,最简单的起点是使用 synchronized 关键字来保护 Tool 类的任何修改状态的方法。详细示例请参见winterbe.com/posts/2015/04/30/…
  • 有没有办法保证整个工具的安全,而不需要查看它的每个方法?因为有时假设这里的工具来自外部库,我就有这样的情况。
  • @RajeshKolappakam,你用什么工具来画这个漂亮的图表?
  • @martin,两种解决方案:(1)让每个线程都有自己的Tool。这样,它就不需要是线程安全的。 (2) 如果线程必须使用共享的Tool,那么让它们也共享一个Lock。确保所有线程在使用Tool.之前锁定Lock
【解决方案3】:

因此,如果 Machine 通过任何方式本身都是线程安全的,那么可以安全地声明“局部变量机器”是线程安全的。

无论它引用的任何对象的线程安全性如何,都可以始终无条件地声明“局部变量machine”是线程安全的。

否则,即使 'machine' 是局部变量,它也不安全。

如果 'it' 引用局部变量,它总是线程安全的。

这种理解正确吗?

没有。您将变量与对象混淆了。

  • 局部变量,例如您的示例中的machine,是线程安全的,句号。
  • 对象是否是线程安全的,取决于它们内部的内容,无论它们在何处以及如何被引用,即在这种情况下,object 是否是 Machine 的实例被局部变量machine引用。

【讨论】:

  • 局部变量是安全的,这并不意味着太多。重要的是它所指的对象。因此,即使对于局部变量,线程安全也很可能仍然是头等大事。
  • @user697911 我就是这么说的。局部变量是线程安全的,这就是问题的答案,我引用的是,“局部变量是线程安全的”是否带有条件?我已经回答了关于所指对象的部分。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-07
  • 2015-07-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多