局部变量的java线程安全
Local variables are always thread safe. Keep in mind though, that the object a local variable points to, may not be so. If the object was instantiated inside the method, and never escapes, there will be no problem.
我不熟悉Java中的多线程,我不明白“对象转义方法”是什么意思。任何人都可以给我看一个代码示例,其中对象通过转义方法变得非线程安全。另外,请解释为什么它变得非线程安全
这是否意味着如果我们简单地将这个对象传递给另一个方法,它将成为非线程安全的
注:对你们中的许多人来说,这听起来可能是一个简单的问题。但对我来说,我读了多篇文章来查看代码示例,但都找不到
# 1 楼答案
对
嗯,它可能会变成非线程安全的:这取决于其他方法对它做了什么
非线程安全的示例如下:
这是线程不安全的,因为其他线程现在可以通过字段访问局部变量引用的对象
当然,只有当值是可变的时,它才会变得不安全。一个不可变的值本质上是线程安全的,所以它可以被传递,存储在字段中,无论什么
一个仍然线程安全的例子可能是:
这仍然是线程安全的(如果使用局部变量作为参数调用),因为
param
是以线程受限的方式使用的(当前执行线程之外的任何内容都看不到它的值)您甚至可以在方法中对其进行更改:
尽管有变异,这仍然是线程安全的,因为仍然只有当前线程可以看到值
# 2 楼答案
如果你一件一件地看,应该不难理解
如果程序中的两个或多个线程访问相同的数据(也称为“共享数据”),则需要确保代码以“线程安全”的方式访问数据
static
变量和共享对象的成员变量(也称为“字段”)在函数调用中将对象引用作为参数传递本身并不允许对象引用“转义”到另一个线程。但是它可以允许它。这完全取决于被调用函数对传递的对象所做的操作。如果您编写的代码在多线程程序中调用函数,您的职责是了解该函数将如何处理您提供给它的对象(例如,该函数是否将与另一个线程共享该对象)
对象共享的一些方式:
将对对象的引用存储到由线程共享的
static
变量中该对象是
Runnable
对象,您将其赋予一个新的Thread
,或者它是Runnable
对象的一个成员变量的引用对象对象是提交给thread pool的
Runnable
或Callable
,或者是提交给线程池的对象的成员变量的引用该对象是之前共享的某个其他对象的成员变量的引用,包括,尤其是
List
或Set
或Map
)Queue
中,该设置专门用于在线程之间共享对象李># 3 楼答案
转义方法意味着:它被使用或存储在方法之外的某个地方
示例:你有一个全局变量计数器,你在局部方法中计算一些东西。现在,只要使用本地计数器,一切都很好,但只要设置globalcounter=localcounter,就不能假设globalcounter==localcounter,因为它总是可以被外部因素更改
# 4 楼答案
Java是一种基于引用的语言。这只是指针的另一个词
当你写作时:
这只是语法:
第1行声明了一个名为“foo”的变量(指针)。 第2行做了两件事:它创建了一个全新的对象
foo
然后更新以引用它。就像"hello"
是宝藏,而foo
是一张宝藏地图foo = "Hello"
创建新的宝藏,将其埋在沙子中,然后在纸上绘制一张宝藏地图;你贴上foo
标签的那张纸。“foo”不是宝藏,说这个字符串是“foo”字符串是不正确的。它不是——它只是宝藏,宝藏没有名字。不可能有地图指向它(这意味着垃圾收集器最终会把它挖出来并扔掉),可能有一千个地图指向它,以及介于两者之间的任何东西。在上面的代码片段中,有一个映射指向它。你的地图。你叫的那个foo
但你可以和其他人分享这张地图。然后他们也能找到你的宝藏
“本地人是不变的”。对他们是。然而,你的局部变量是
foo
变量,而foo
不是宝藏。这是地图。这是你的地图。没人能搞糟它。地图看起来会有任何不同的唯一方式是,如果您在自己的代码中编写foo =
某个地方。再多地将foo
传递给其他方法也不会改变这个映射你读到的文本所指的是,唯一不变的东西是你的地图。地图指向的宝藏?谁知道呢。如果你把地图交给其他人,他们不能更改你的地图,但他们可以复制。他们可以跟随它。他们可以挖掘宝藏,然后把它砸碎。它们不会影响你的地图,但如果你按照你的地图走,你会发现什么?如果你和其他人分享宝藏的位置,现在可能完全不同了
现在,对于弦来说,这是一个没有实际意义的观点:弦的宝藏是不可战胜的。它们不能以任何方式被粉碎或修改。它们是不可变的对象,没有改变它的方法,也没有公共(非最终)字段。但并不是所有的物体都是这样的。有些宝藏可以改变或打碎。例如,一个简单的列表:
在上面的代码中,你不知道它打印什么,因为你不知道foo做什么。你知道你的
x
不可能打印null
。空指的是你有一张空白的藏宝图,没有人能弄乱你的藏宝图。但是foo
会弄乱宝藏:这没有任何作用。这个方法可以得到一份你的藏宝图。然后它创造新的宝藏,把它埋在沙子里,拿一块橡皮擦到它的
x
宝藏地图(用来保存你的一份),然后在上面画一张全新的宝藏地图,其中X标记了新创造的宝藏的位置。这绝对不会对你的地图或你的地图所指向的宝藏产生任何影响。您的代码将继续打印[Hello]
然而:
这是完全不同的。这将获取你给它的藏宝图副本,跟随它并向下挖掘(
.
是java ese的意思:跟随地图并挖掘)。然后它打开箱子,把“世界”放进去(从技术上讲,它把“世界”宝藏的地图放进去,字符串也是对象,因此是基于引用的)如果你以后跟着地图挖,你会看到的。您的代码将打印
[Hello, World]
这就是课文所说的。通过复制,或使用不可变对象,或意识到地图所指向的任何宝藏可能已被其他代码更改(如果您共享了地图),来避免它