读书人

线程保险学习笔记(二)

发布时间: 2012-08-27 21:21:57 作者: rapoo

线程安全学习笔记(二)
两个常来说明volatile的例子:
例子1:


测试类:

输出结果:
All threads count 1698 times!!
Thread 0 count 1000 times!
Thread 1 count 1000 times!

例子2:
package test;import java.util.Vector;import com.maximilian.www.MyTestThread2;public class MyTest2{private static int threadNum = 2;private static int threadId;private static Vector<MyTestThread2> threads = new Vector<MyTestThread2>();public static void main (String [] args){    for(threadId=0;threadId < threadNum ;threadId++)    {    MyTestThread2 t = new MyTestThread2(threadId);    threads.add(t);    }    for(Thread t:threads)    {    t.start();    }    for(Thread t:threads)    {    try            {            t.join();            } catch (InterruptedException e)            {            // TODO Auto-generated catch block            e.printStackTrace();            }    }        System.out.println("lowerLimit:"+MyTestThread2.getLowerLimit()+"\n upperLimit:"+MyTestThread2.getUpperLimit());}}

测试结果:
lowerLimit:4
upperLimit:3

从上面的两个例子可以看出, volatile修饰的变量至少从操作的角度来看不是线性进行的。
一般的普通的对变量的操作过程:

多线程的情况下就会发生:

通过上面例子,我们可以知道,即使对变量进行了volatile申明还是有上面图中的现象寻在,例子1中计数操作有线程的操作直接被覆盖,对于例子2两个有内在联系的变量的操作也是因为这种读取-修改-更新的非原子性导致的,有点写逻辑的时候因为延时出现的竞争冒险现象(写逻辑出身伤不起)。
那么volatile加了有什么作用的?对volatile变量在线程本地工作区中不做缓存,对volatile的读写总是指向堆中的引用。这个类似于告诉线程这个变量在本身的存储空间上的值是不可信的,每次要用到就要去公共内存上读取,并且会要求线程在修改完成后及时更新住内存(有些操作对对象连续操作可能不会及时每变一次更新),这样就保证了线程的操作只要完成就可以被其他线程看到。
Volatile对于新手来说比较难用,但是因为他的性能好于syncronized以及没有锁的同步,在高手手里还是个宝。
应用场景:
1.状态标志指示发生了一个重要的一次性事件,例如完成初始化或请求停机;
2.一次性安全发布。在1.5以后貌似是可以解决双重检查锁定单例中的问题。
http://www.cnblogs.com/melode11/archive/2008/09/28/1301114.html
http://www.ibm.com/developerworks/cn/java/j-dcl.html
3.独立观察,定期 “发布” 观察结果供程序内部使用。
4.volatile bean 模式。
5.结合volatile和syncronized的开销较低的读-写锁策略。

读书人网 >编程

热点推荐