编写安全的线程就是对共享数据的操作不出现问题,通过同步使来避免多个线程同一时刻方位共享数据,或者共享和发布对象,从而使能够安全地由多个线程同时访问。
可见性:
public class NoVisibility {
private static boolean ready;
private static int number;
public 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;
}
}
这段代码不推荐这么做,因为代码中没有使用足够的同步机制,无法保证主线程写入的值对于读线程来说是可见的。
实际上说就是主线程跟读线程共享变量number跟ready,主线程写入变量的值得时候,读线程很有可能看不到主线程写的值,程序的执行顺序可能不是我们想象中的那样,即程序可能会持续循环下去。(不过在我本机测试多少次,都是输出42,不知为何正常运行)
失效数据:
由于不同步的存在,访问的共享变量可能是更新后的最新值,也可能是以前的失效值。
当线程在没有同步的情况下读取变量,可能会得到一个失效值,至少这个值有之前的变量设置的值,而不是一个随机值,这种安全性被称为最低安全性。不过存在一个例外条件,就是非volatile类型的long或double变量,如果读写操作在不同的线程中执行,很有可能得到某个高32位或者低32位的随机值。
Volatile变量:
volatile boolean asleep;
while(!asleep)
countSomeSleep();
这段代码还是蛮有意思的 说某天失眠了,通过数羊来解决睡眠问题,然而入睡又是个多方面原因,这个可以看成多个线程在影响你是否入睡,asleep这个参数被多个线程控制,为了确保你现在是否真的睡着,asleep这个变量总是的到的最新值。
volatile提供一种比加锁机制稍弱的同步机制,确保这个变量一直被共享。加锁机制既可以确保可见性以及原子性,然而volatile智能确保可见性。volatile使用必须满足的条件:
对变量的写入操作不依赖变量的当前值,或者能确保只有单个线程更新变量的值。
该变量不会与其他状态变量一起纳入不变性条件中。
在访问变量时不需要加锁。
线程发布与逸出:
这部分内容现在感觉还晦涩难懂,以后再来说。
线程封闭:一种避免使用同步的方式就是不共享数据。如果数据都被封闭在各自的线程之中,就不需要同步。这种通过将数据封闭在线程中而避免使用同步的技术称为线程封闭。
1.Ad-hoc线程封闭
由于封闭技术的脆弱性,因此尽量少用它。
2.栈封闭
下边的内容读起来有困难,先跳过这一章。