gpt4 book ai didi

java - 从内部类线程访问外部字段(非最终)是否线程安全?

转载 作者:塔克拉玛干 更新时间:2023-11-01 21:48:36 25 4
gpt4 key购买 nike

基本上以下工作,但自从我读到 final 关键字后,我不确定如果不同的线程访问它是否必须声明 name final?

提前致谢。

public class Test4 {

// to ensure thread-safety do we have to declare the variable name final ?
private String name;

public Test4 (String name) {
this.name = name;
}

public void start() {
new MyThread().start();
}

private class MyThread extends Thread {

public void run() {
System.out.println(name);
}
}

public static void main(String[] args) {
Test4 t = new Test4("Don't know if I am threadsafe");
t.start();
}

}

最佳答案

final 修饰符 - 在防止成员被重新分配的同时 - 不会影响给定代码的正确性 1

来自17.4.4 Synchronization Order Java 5 语言规范部分:

A synchronization order is a total order over all of the synchronization actions of an execution .. Synchronization actions induce the synchronized-with relation on actions, defined as follows:

  • ..
  • An action that starts a thread synchronizes-with the first action in the thread it starts.
  • ..

然后,由于设置 name 成员的线程是启动 线程的线程,因此保证了同步顺序。 (同步意味着一个 Happens-before ordering 。)

注意:

  • 成员 name 只需在启动线程之前 设置:也就是说,不需要在构造函数中设置此同步保证。
  • 保证同步顺序 - 因此它保证在已经运行的线程或在别处创建的线程之间发生先行或值可见性!

但是,final 字段确实给人一种更舒适的感觉(引用 17.5 Final Field Semantics):

An object is considered to be completely initialized when its constructor finishes. A thread that can only see a reference to an object *after that object has been completely initialized is guaranteed to see the correctly initialized values for that object's final fields.

在这种情况下,对于 final 字段,该值保证在构造函数完成后在每个 线程上可见。 ("constructor leaks" 可能违反此保证。)


1 在提供的代码中,“非最终”name 成员仅在线程启动之前分配一次。

不同中,不那么琐碎的程序可能会暴露其他同步问题。此答案检查删除 final 是否会改变所提供代码的正确性。

综上所述,我认为同时使用不可变变量 (final) 和不可变对象(immutable对象)是“良好做法”——尤其是在处理线程时。无需了解 JVM 的神秘细节,而是做安全可靠的事情并力求明显的正确性而不是聪明或“性能”。

另见:

关于java - 从内部类线程访问外部字段(非最终)是否线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14354620/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com