3.1 可见性
当多个线程访共享变量时,如果没有正确的同步机制,那么这些线程之间对对象的操作是互相不可见的。
public class NoVisibility {
private static boolean ready;
private static int number;
private static class ReaderThread extends Thread{
public void run() {
while(!ready) {
Thread.yield();
System.out.println(number);
}
}
}
public static void main(String[] args) {
new ReaderThread().start();
number = 42;
ready = true;
}
}
这个方法启动两个线程,一个主线程,一个ReaderThread线程,结果很有可能readerThread线程永远都读取不到number的值。也有可能,会输出0.也就是说看到了ready的值,却没有读取到number的值。这种现象称为重排序。
在没有同步的情况下,编译器、处理器、运行时等都可能会对操作的执行顺序进行一些意想不到的调整。
加锁的含义不仅仅局限于互斥行为,还包括内存的可见性。为了确保所有的线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。
3.1.4: Volatitle变量
被volatitle修饰的变量,是能保证对象的可见性。但是不能保证对象的原子性。
当且仅当满足以下所有条件时,才应该使用volatitle变量。
1.只有单个线程更新变量的值,或着对变量的值的写入操作不依赖当前值。
2.该变量不会与其它状态变量一起纳入不变性条件中。
3.在访问变量时不需要加锁。
3.2 发布与逸出
发布对象:是指对象能够在当前作用域之外的代码中使用。
逸出:当某个不应该发布的对象被发布时,就称为逸出。(我理解为,如果一个对象被发布,但是无法保证其线程安全,就是逸出。)