美文网首页
Java 多线程(一)线程安全基础

Java 多线程(一)线程安全基础

作者: 闲相思 | 来源:发表于2020-06-08 17:34 被阅读0次

    线程安全基础

    最低安全性

    当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值。这种安全性保证称为最低安全性。

    最低安全性适用于绝大多数变量,但是存在一个例外,非 volatile 类型的64位数值变量(double 和 lang)。Java 内存模型要求,变量的读取操作和写入操作必须是原子操作,但对于非 volatile 类型的 long 和 double 变量,JVM 允许将64位的读操作或写操作分解为两个32位的操作。

    Volatile 变量

    一种稍弱的同步机制,用来确保将变量的更新操作通知到其他线程。当声明为 volatile 类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile 变量不会被缓存到寄存器或者其他处理器不可见的地方,因此在读取 volatile 类型的变量是总会返回最新写入的值。

    加锁机制即可以保证可见性又可以保证原子性,而 volatile 变量只能确保可见性。

    • volatile 使用条件(当且仅当)
      • 对变量的写入操作不依赖变量的当前值,或者确保只有单个线程更新变量值。
      • 该变量不会与其他状态变量一起纳入不变性条件中。
      • 在访问变量时不需要加锁。

    线程封闭

    避免使用同步,在单线程内访问数据。可靠的线程封闭技术包括栈封闭ThreadLocal

    Ad-hoc 线程封闭

    维护线程封闭性的职责完全由程序实现来承担。该方式是非常脆弱的。
    可以通过在 volatile 变量上实现一种特殊的线程封闭。
    确保只有单个线程对共享的 volatile 变量执行写入操作,
    那么就可以安全的就可以安全的在这些共享的 volatile 变量上执行·读取·-·修改·-·写入·的操作。
    在这种情况下,相当于将修改操作封闭在单个线程中以防止发生竟态条件,并且 volatile 变量还确保了其可见性。
    

    栈封闭

    线程封闭的一种特例,栈封闭中,只能通过局部变量才能访问对象。
    局部变量的固有属性之一就是封闭在执行线程中。
    它们位于执行线程的栈中,其他线程无法访问这个栈。
    

    ThreadLocal 类

    源码详解点这里

    ThreadLocal 提供了 get 和 set 等访问接口和方法。
    这些方法为每个使用该变量的线程都存有一份独立的副本,
    因此 get 总是返回由当前执行线程在调用 set 时设置的最新值。
    

    不变性

    不可变对象

    某个对象在创建后其状态不能被修改,那么这个对象就称为不可变对象。

    不可变对象很简单,它们只有一种状态,并且该状态由构造函数控制。
    

    Final 域

    final 用于构建不可变性对象。final 类型的域是不可修改的(但如果 final 域所引用的对象是可变的,那么这些被引用的对象是可以修改的)
    深入理解 final 关键字

    final 域能确保初始化过程的安全性,从而可以不受限制的访问不可变对象,并在共享这些对象时无需同步。
    

    安全发布对象

    要安全发布一个对象,对象的引用和状态必须同时对其他线程可见。
    一个正确构造的对象可以通过以下方式来安全发布。
        * 在静态初始化函数中初始化一个对象引用
        * 将对象的引用保存到 volatile 类型的域或AtomicReferance中
        * 将对象的引用保存到某个正确构造对象的 final 域中
        * 将对象的引用保存到由锁保护的域中
    

    相关文章

      网友评论

          本文标题:Java 多线程(一)线程安全基础

          本文链接:https://www.haomeiwen.com/subject/dxzrtktx.html