java内存模型要求变量的读取操作和写入操作都必须是原子操作,但对于非volatile类型的64位数值变量(double,long),jvm允许将64位的读操作或写操作分解为两个32位的操作。当读取一个非volatile类型的long变量时,如果对该变量的读操作和写操作在不同的线程中执行,那么很可能会读取到某个值的高32位和另一个值的低32位。因此,即使不考虑失效数据问题,在多线程程序中使用共享且可变的long和double等类型的变量也是不安全的,除非使用volatile来声明他们或者用锁保护起来。
加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能确保可见性。
把变量声明为volatile类型后,编译与运行时都会注意到这个变量是共享的,因此不会讲该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存到寄存器或者对其他处理器不可见的地方,因此在读取volatile变量时总会返回最新写入的值。
比如,while循环的条件变量,如果监视是否改变,需要设置为volatile
volatile boolean asleep; ... while(!asleep) countSomeSheep();
发布(Publish)一个对象是指:使对象能够在当前作用域之外的代码中使用。
在许多情况,我们要确保对象及其内部状态不被发布。而在某些情况,我又需要发布该对象,但如果在发布时要确保线程安全性,则可能需要同步。发布内部状态可能会破坏封装性,使线程难以维持不变的状态。例如,如果在对象构造完成之前就发布该对象,就会破坏线程安全性。
发布对象的最简单的方法是将对象的引用保存到一个共有的静态变量中。
逸出(Escape):当某个不应该发布的对象呗发布时。
程序list 3-6
class UnsafeStates{ private String[] states = new String[]{"as","dsf",...}; public String[] getStates(){return states;} }
如果按上述的方式发布states,则任何调用者都可以修改数组,这是不安全的。
原文:http://www.cnblogs.com/woshimrf/p/5238827.html