---
title: final域
description: "使用final域标记的变量，编译器和CPU需要遵守两个重排序规则："
url: https://www.hikunpeng.com/document/detail/zh/kunpenggrf/codeprtr/kunpengtaishanporting_12_0082.html
sourcePath: /source/zh/kunpenggrf/codeprtr/kunpengtaishanporting_12_0082.html
indexId: 2492a7085b589ee34e6c4b483be396010e022e43c8a77a02e13827e52551626665
---
# final域

使用final域标记的变量，编译器和CPU需要遵守两个重排序规则：

构造函数内对一个final域的写入，与随后把该被构造对象的引用赋值给一个引用变量，这两个操作不能重排序。

初次读一个包含final域的对象的引用，与随后初次读这个final域， 这两个操作不能重排序。

写入示例如下：

```
public class FinalDemo {
int i;          // 普通变量
final int j;    // final 变量
static FinalDemo obj;
public FinalDemo {  // 构造函数
i = 1;          // 写普通域
j = 2;          // 写 final 域
}
public static void write() {    // 写线程 A 执行
obj = new FinalDemo();
}
public static void read() { // 读线程 B 执行
FinalDemo object = obj; // 读对象引用
int a = object.i;       // 读普通域
int b = object.j;       // 读 final 域
}
}
```

下图是一种上述代码的执行时序：


在图中，写普通域的操作被编译器重排序到构造函数之外，线程B读到了i未初始化的值。而写final域的操作，被写final域的重排序规则“限定”在了构造函数之内，线程B能正确读到final变量初始后的值。


在图中，读对象的普通域被重排序到读对象引用之前。读普通域时，该域还没被写线程A写入，这是一个错误的读取操作。而final域的读操作会被“限定”在对象引用之后，此时final域已经被正确初始化。
