《Java Concurrency in Practice》之可见性(Visibility)

来源:互联网 发布:虚拟专用网络是免费的 编辑:程序博客网 时间:2024/06/05 15:35
    原文:Visibility is subtle because the things that can go wrong are so counterintuitive.    译文:可见性是微妙的,因为可能出错的事情是如此的有悖常理。
    public class NoVisibility {private static boolean ready;private static int number;private static class ReaderThread extends Thread {@Overridepublic void run() {while (!ready) {Thread.yield();}System.out.println(number);}}public static void main(String[] args) {new ReaderThread().start();number = 42;ready = true;}    }
        NoVisibility可能会持续循环下去,因为读线程可能永远都看不到ready的值。
        一种更奇怪的现象是会发生重排序(Reordering),NoVisibility可能会输出0,因为读线程可能看到了写入ready的值,但却没看到之后写入number的值。
        在没有同步的情况下,编译器(Compiler)、处理器(Processor)和运行时(Runtime)等都可能对操作的执行顺序进行一些意想不到的调整。在缺乏足够同步的多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得出正确的结论。
一、失效数据(stale data)
        NoVisibility展示(demonstrated)的一种方式,在缺乏足够的同步程序中,可能会导致令人惊讶的结果:失效数据。(原文:NoVisibility demonstrated one of the ways that insufficiently synchronized programs can cause surprising results: stale data.)
        失效数据还可能会带来诸如损坏的数据结构(corrupted data structures)、不精确的计算(inaccurate computations),以及无限循环(infinite loops)等。
二、非原子的64位操作(Nonatomic 64-bit operations)
        线程的最低安全性(out-of-thin-air safety),是指当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值。
        最低安全性适用于绝大数变量,但是存在一个例外:非volatile类型的64位数值变量(double and long)。Java的内存模型要求,变量的读取操作和写入操作都必须是原子操作,但对于非volatile类型的long和double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作。
        因此,在多线程中使用共享且可变的long和double等类型的变量也是不安全的,除非它们用volatile声明,或者由锁保护。
三、加锁和可见性(Locking and visibility)
        内置锁可以用于确保某个线程以一种可预测的方式来查看另一个线程的执行结果。
        在访问共享的可变变量时,我们有理由要求所有线程在同一个同步锁的规则,保证由某一个线程写的值对其它线程是可见的。否则,如果一个线程在未持有正确锁的情况下,读取某个变量,可能会看到一个失效的值。(原文:We can now give the other reason for the rule requiring all threads to synchronize on the same lock when accessing a shared mutable variable—to guarantee that values written by one thread are made visible to other threads. Otherwise, if  a thread reads a variable without holding the appropriate lock, it might see a stale value.)
        加锁不仅仅是与互斥性相关,也与内存的可见性相关。为了确保所有线程都能看到共享变量的最新值,读写线程必须在同一个锁上同步。(原文:Locking is not just about mutual exclusion; it is also about memory visibility. To ensure that all threads see the most up-to-date values of shared mutable variables, the reading and writing threads must synchronize on a common lock.)

0 0
原创粉丝点击