想要使用多线程编程,有一个很重要的前提,那就是必须保证操纵的是线程安全的类.
那么如何构建线程安全的类呢? 1. 使用同步来避免多个线程在同一时间访问同一数据. 2. 正确的共享和安全的发布对象,使多个线程能够安全的访问它们.
那么如何正确的共享和安全的发布对象呢? 这正是这篇博客要告诉你的.
1. 多线程之间的可见性问题.
为什么在多线程条件下需要正确的共享和安全的发布对象呢?
这要说到可见性的问题:
在多线程环境下,不能保证一个线程修改完共享对象的数据,对另一个线程是可见的.
一个线程读到的数据也许是一个过期数据,这会导致严重且混乱的问题,比如意外的异常,脏的数据结构,错误的计算和无限的循环.
举个例子:
public class NoVisibility { private static int num; private static boolean ready; private static class RenderThread extends Thread{ @Override public void run(){ while(!ready){ Thread.yield(); } System.out.println("num = " + num); } } public static void main(String [] args) throws InterruptedException { new RenderThread().start(); num = 42; ready = true; } }
new RenderThread().start()表示创建一个新线程,并执行线程内的run()方法 ,如果ready的值是false,执行Thread.yield()方法(当前线程休息一会让其他线程执行),这时候再交给main方法的主线程执行,给num赋值42,ready赋值true,然后在任务线程中输出num的值.因为可见性的问题,任务线程可能没有看到主线程对num赋值,而输出0.
我们接下来来看看发布对象也会引发的可见性问题.
2. 什么是发布一个对象
发布: 让对象内被当前范围之外的代码所使用.
public class Publish { public int num1; private int num2; public int getNum2(){ return this.num2; } }
无论是 publish.num1 还是 publish.getNum2()哪种方法,只要能在类以外的地方获取到对象,我们就称对象被发布了.
如果一个对象在没有完成构造的情况下就发布了,这种情况叫逸出.逸出会导致其他线程看到过期值,危害线程安全.

