java - final 关键字究竟对并发性有什么保证?

标签 java multithreading concurrency

我想我已经读过字段上的 final 关键字保证如果线程 1 实例化包含该字段的对象,那么如果线程 2 具有对该对象的引用,那么线程 2 将始终看到该字段的初始化值(前提是其构造正确)。它还在 JLS 中说

[Thread 2] will also see versions of any object or array referenced by those final fields that are at least as up-to-date as the final fields are. (section 17.5 of JLS)

这意味着如果我有 A 类

class A {
  private final B b = new B();
  private int aNotFinal = 2;
  ...

和B类

class B {
  private final int bFinal = 1;
  private int bNotFinal = 2;
  ...

那么 aNotFinal 不能保证在线程 2 获得对类 A 的引用时被初始化,但字段 bNotFinal 是,因为 B 是一个由 final 字段引用的对象,如 JLS 中所指定。

我有这个权利吗?

编辑:

如果我们有两个线程同时在类 C 的同一个实例上执行 getA(),则可能发生这种情况

class C {
  private A a;

  public A getA(){
    if (a == null){
      // Thread 1 comes in here because a is null. Thread B doesn't come in 
      // here because by the time it gets here, object c 
      // has a reference to a.
      a = new A();
    }
    return a; // Thread 2 returns an instance of a that is not fully                     
              // initialized because (if I understand this right) JLS 
              // does not guarantee that non-final fields are fully 
              // initialized before references get assigned
  }
}

最佳答案

你说的是真的。

将字段标记为 final 会强制编译器在构造函数完成之前完成字段的初始化。但是,对于非最终字段,没有这样的保证。这可能看起来很奇怪,但是编译器和 JVM 出于优化目的做了很多事情,例如重新排序指令,这会导致此类事情发生。

final 关键字还有很多好处。来自Java Concurecency in Practice:

Final fields can't be modified (although the objects they refer to can be modified if they are mutable), but they also have special semantics under the Java Memory Model. It is the use of final fields that makes possible the guarantee of initialization safety (see Section 3.5.2) that lets immutable objects be freely accessed and shared without synchronization.

书上说:

To publish an object safely, both the reference to the object and the object's state must be made visible to other threads at the same time. A properly constructed object can be safely published by:

  • Initializing an object reference from a static initializer;
  • Storing a reference to it into a volatile field or AtomicReference;
  • Storing a reference to it into a final field of a properly constructed object; or
  • Storing a reference to it into a field that is properly guarded by a lock.

关于java - final 关键字究竟对并发性有什么保证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27254152/

相关文章:

java - ConcurrentHashMap 上的竞争条件问题

java - eclipse 中的 Junit 在使用 junit 时产生 NoClassDefFoundError

访问 hashmap 时出现 java.util.ConcurrentModificationException

multithreading - 使用 bash 进行多线程

java - 如何在一个套接字上发送各种信息?

asp.net-mvc - 未检查 Web API 的并发检查

java - 在 Android 中将数据从 Activity 传递到 Fragment

java - 传递数组并排序

java - 第二个 AsyncTask 没有执行

mysql - 在 mysql 中插入行时锁定