Open chengfengjie opened 6 years ago
可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。在单线程环境中,如果向某个变量先写入值,如果在没有其他写入操作的情况下读取这个变量,那么总能得到相同的值。这看起来很自然,然而,当读操作和写操作在不同的线程执行时,情况并非如此。我们无法确保执行读操作的线程能适时的看到其他线程写入的值,为了确保多个线程之间对内存的写入操作的可见性,必须用同步机制。
在没有同步的情况下,编译器、处理器以及运行时都可能对操作的执行顺序进行一些意想不到的调整,在缺乏足够同步的程序中,想要对内存操作的执行顺序进行判断,几乎无法得出正确的结论
Java内存模型要求,变量的读取操作和写入操作都必须是原子操作,但是对于非volatile类型的long和double变量,JVM允许将64位的读操作和写操作分解为两个32位的操作,当读取一个非volatile类型的long变量时,如果对该变量的读操作和写操作在不同的线程执行,那么可能读取到某个数值的高32位和另一个值的低32位。因此:在多线程中使用共享且可变的long和double等类型变量也是不安全的,除非用关键字volatile
来声明他们,或者用锁保护起来
当访问共享的可变数据时,通常需要使用同步。一种避免使用同步的方式就是不共享数据。如果仅仅在单线程内访问数据,就不需要同步,这种技术被称为线程封闭(Thread Confinement).他是实现线程安全最简单的方式之一。
Ad-Hoc线程封闭是指维护线程封闭性的职责完全有程序实现来承担。由于Ad-Hoc线程封闭技术的脆弱性,因此在程序中尽量少用它,在可能的情况下,应该使用更强的线程封闭技术(栈封闭或ThreadLocal类)
不可变对象一定是线程安全的,当满足以下条件时,对象才是不可变的:
final
类型this
引用没有溢出)除非需要更高的可见性,否则将所有的域都声明为私有域。
除非需要某个域是可变的,否则应当其声明为final
域。
在访问共享的可变状态时需要进行正确的管理。
synchronized
的作用: