多线程(56)final关键字在Java内存模型中的作用

在Java中,final关键字可以用于变量、方法和类。当用于变量时,final确保变量一旦被初始化后其值就不能被改变;用于方法时,确保方法不被重写;用于类时,确保类不被继承。

对于Java内存模型(JMM)来说,final字段的主要作用是提供初始化安全性,确保对象一旦被构造完成,其final字段的值就不会被改变,并且对于任何获取这些字段的线程来说,final字段的值总是一致的。

final字段的内存语义

在JMM中,写入final字段的重排序规则确保了构造函数内对一个final字段的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个动作不能被重排序。这种重排序会在构造函数内对final字段的所有写入操作之后执行,这意味着对象的引用直到final字段被正确初始化之后才能从构造函数中逸出。

代码演示

java 复制代码
public class FinalFieldExample {
    final int x;
    int y;
    static FinalFieldExample f;

    public FinalFieldExample() {
        x = 3;  // 对final字段的写入
        y = 4;  // 对普通字段的写入
    }

    static void writer() {
        f = new FinalFieldExample();
    }

    static void reader() {
        if (f != null) {
            int i = f.x;  // 读操作
            int j = f.y;  // 读操作
        }
    }
}

在这个示例中,一旦FinalFieldExample对象通过构造函数完全构造后,任何线程都可以保证看到final字段x的值为3,而无论是否有同步。但是对于普通字段y,如果没有适当的同步,其他线程可能看不到初始化后的值。

初始化安全性

对于包含final字段的对象,JMM提供了一种特殊的保证,称为初始化安全性。这意味着,对于被正确构造的(构造过程中没有this逸出)不可变对象,其他线程都能看到final字段在构造器中设置的值,即使没有同步措施,这个保证也是有效的。

初始化安全性可以保障在对象构造完成后,任何线程访问对象的final字段都将获取到与构造器中一样的值。

源码层面解析

在JDK的源码中,final字段的特殊处理主要体现在JVM的内存屏障插入策略中。在构造函数中写入final字段时,JVM会在构造函数末尾插入一个StoreStore屏障,确保final字段的赋值操作不会被重排序到构造函数之外。

同时,初始化安全性的保证意味着当构造函数完成时,所有对final字段的写入都将在任何后续读取这些字段之前发生内存屏障。

注意事项

  • final字段一旦被初始化后,其语义保证了不可变性,这对于创建不可变对象至关重要。
  • 初始化安全性确保只要对象被正确构造,所有线程都能看到final字段在构造器中被设置的值,即使没有额外的同步措施。
  • 尽管final字段对可见性提供了保证,但它并不能替代所有同步需要。对于涉及多个字段的复杂状态的对象,你可能仍然需要使用synchronizedjava.util.concurrent包中的同步机制。

final字段的使用是创建线程安全的不可变对象的基础,并且可以在没有锁的情况下减少同步的需求,从而提高并发性能。然而,设计线程安全的共享对象依然需要仔细考量,并且通常需要多种同步机制的结合使用。

相关推荐
MC丶科7 小时前
【SpringBoot常见报错与解决方案】中文乱码?Spring Boot 统一解决前后端中文乱码问题(含 Postman 测试)!别再百度“加 UTF-8”了!
spring boot·后端·postman
XXOOXRT11 小时前
基于SpringBoot的加法计算器
java·spring boot·后端·html5
moxiaoran575312 小时前
Go语言的错误处理
开发语言·后端·golang
短剑重铸之日18 小时前
《7天学会Redis》特别篇: Redis分布式锁
java·redis·分布式·后端·缓存·redission·看门狗机制
小北方城市网18 小时前
SpringBoot 全局异常处理与接口规范实战:打造健壮可维护接口
java·spring boot·redis·后端·python·spring·缓存
hanqunfeng18 小时前
(三十三)Redisson 实战
java·spring boot·后端
小北方城市网19 小时前
SpringBoot 集成 MyBatis-Plus 实战(高效 CRUD 与复杂查询):简化数据库操作
java·数据库·人工智能·spring boot·后端·安全·mybatis
hanqunfeng20 小时前
(四十)SpringBoot 集成 Redis
spring boot·redis·后端
小北方城市网21 小时前
SpringBoot 集成 MinIO 实战(对象存储):实现高效文件管理
java·spring boot·redis·分布式·后端·python·缓存
程序员泠零澪回家种桔子21 小时前
RAG自查询:让AI精准检索的秘密武器
人工智能·后端·算法