对象引用什么时候被其他线程可见?final关键字重排序规则?final关键字详解?

重排序是编译器和处理器的默认行为,旨在提高性能,但在多线程环境中可能引发问题,因此需要通过同步机制进行控制。

final关键字详解

final ,用于修饰类、方法和变量。它的主要作用是限制继承、重写和修改,从而增强代码的安全性、可读性和性能优化。


  1. final 修饰变量
    • 作用:final 修饰的变量一旦被赋值,其值不可更改。
    • 分类:
      • 局部变量:必须在声明时或使用前赋值,且赋值后不可修改。
      • 成员变量:必须在声明时、构造方法中或初始化块中赋值,且赋值后不可修改。
      • 静态变量(类变量):必须在声明时或静态初始化块中赋值,且赋值后不可修改。
    • 示例:
      final int x = 10;
      // x = 20; // 编译错误,x 不可修改
      
    • 注意:
      • 对于引用类型变量,final 限制的是引用不可变,但对象内部的状态可以修改。
      • 例如:
        final List<String> list = new ArrayList<>();
        list.add("Hello"); // 合法
        // list = new ArrayList<>(); // 编译错误
        

  1. final 修饰方法
    • 作用:final 修饰的方法不可被子类重写。
    • 适用场景:
      • 当方法的行为已经固定,不希望子类改变其实现时使用。
      • 例如,Object 类中的 getClass() 方法就是 final 方法。
    • 示例:
      class Parent {
          final void show() {
              System.out.println("Parent");
          }
      }
      class Child extends Parent {
          // void show() { // 编译错误,无法重写 final 方法
          //     System.out.println("Child");
          // }
      }
      

  1. final 修饰类
    • 作用:final 修饰的类不可被继承。
    • 适用场景:
      • 当类的设计已经完善,不希望被扩展时使用。
      • 例如,Java 中的 StringInteger 等类都是 final 类。
    • 示例:
      final class MyClass {
          // 类内容
      }
      // class SubClass extends MyClass { // 编译错误,无法继承 final 类
      // }
      

  1. final 关键字的优势
    • 安全性:防止变量被意外修改,或类和方法被不恰当地扩展或重写。
    • 可读性:明确表明变量、方法或类的不可变性,便于理解和维护。
    • 性能优化:final 变量和方法可以被 JVM 优化,例如内联优化(inline optimization)。

  1. final 与不可变对象
    • 不可变对象:对象的状态在创建后不可修改。
    • 关系:final 关键字是实现不可变对象的重要手段。
    • 示例:
      public final class ImmutableClass {
          private final int value;
          public ImmutableClass(int value) {
              this.value = value;
          }
          public int getValue() {
              return value;
          }
      }
      

  1. final 的使用注意事项
    • 过度使用:滥用 final 可能导致代码灵活性降低,应适度使用。
    • 与并发编程的关系:final 变量在多线程环境下是线程安全的,因为其值不可变。

final关键字重排序规则

final修饰的数据类型分类

  1. 基本数据类型

    • final域写:
      • 规则:禁止将final域的赋值操作重排序到构造方法之外。
      • 目的:确保当一个对象对所有线程可见时,其所有final域都已经正确初始化。
      • 关键点:final域的赋值必须在构造方法内完成,不能延迟到构造方法之外。
    • final域读:
      • 规则:禁止初次读取对象的引用与读取该对象包含的final域的重排序。
      • 目的:保证在读取对象引用时,其final域的值已经正确初始化。
      • 关键点:初次读取对象引用和读取final域的操作必须按顺序执行,不能重排序。
  2. 引用数据类型

    • 扩展规则:
      • 在基本数据类型的规则基础上,增加一条约束:禁止在构造函数中对final修饰的对象的成员域的写入与随后将该对象的引用赋值给引用变量重排序。
    • 目的:确保在将对象的引用赋值给引用变量时,其final域的成员已经正确初始化。
    • 关键点:如果final域是一个引用类型,那么对该引用类型成员的赋值操作不能与将对象引用赋值给变量的操作重排序。

总结

  • 基本数据类型:final域的赋值必须在构造方法内完成,且读取对象引用和读取final域的操作不能重排序。
  • 引用数据类型:在基本数据类型规则的基础上,增加对final域成员赋值的顺序约束,确保在对象引用赋值时,其final域成员已经初始化。

这些规则共同保证了final域在多线程环境下的可见性和正确性,避免了由于重排序导致的线程安全问题。

对象引用什么时候被其他线程可见

对象引用对其他线程的可见性是一个与 Java 内存模型(JMM) 相关的复杂问题。对象引用的可见性取决于多个因素,包括 变量的修饰符、线程同步机制 以及 对象的初始化过程。

  1. 普通变量(非 final 和非 volatile)
    • 默认情况:普通变量的写操作对其他线程不可见,因为 JMM 允许线程将变量值缓存在本地内存中。
    • 问题:一个线程修改了对象引用,其他线程可能仍然看到旧值。
    • 示例:
      class MyClass {
          Object obj;
          void setObj(Object obj) {
              this.obj = obj;
          }
      }
      
      在多线程环境中,obj 的修改对其他线程可能不可见。

  1. volatile 修饰的变量
    • 作用:volatile 修饰的变量对所有线程可见,写操作会立即刷新到主内存,读操作会从主内存读取最新值。
    • 适用场景:适合用于标记状态或简单的共享变量。
    • 示例:
      class MyClass {
          volatile Object obj;
          void setObj(Object obj) {
              this.obj = obj; // 写操作对其他线程可见 
          }
      }
      

  1. final 修饰的变量
    • 作用:final 修饰的变量在构造方法完成后对其他线程可见,且不会被重排序到构造方法之外。
    • 适用场景:适合用于不可变对象或线程安全的初始化。
    • 示例:
      class MyClass {
          final Object obj;
          MyClass(Object obj) {
              this.obj = obj; // 构造方法完成后,obj 对其他线程可见 
          }
      }
      

  1. 同步机制(synchronized、Lock)
    • 作用:通过同步机制(如 synchronizedLock)可以确保变量修改对其他线程可见。
    • 适用场景:适合用于复杂的线程同步场景。
    • 示例:
      class MyClass {
          Object obj;
          synchronized void setObj(Object obj) {
              this.obj = obj; // 写操作对其他线程可见 
          }
      }
      

  1. 对象的初始化与可见性
    • 问题:如果对象未正确初始化,其他线程可能看到部分初始化的对象。
    • 解决方案:使用 final 或同步机制确保对象初始化完成后对其他线程可见。
    • 示例:
      class MyClass {
          private final Object obj;
          MyClass(Object obj) {
              this.obj = obj; // 构造方法完成后,obj 对其他线程可见 
          }
      }
      

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值