volatile关键字 学习记录1

虽然已经工作了半年了...虽然一直是在做web开发....但是平时一直很少使用多线程.....

然后最近一直在看相关知识..所以就有了这篇文章

 

用例子来说明问题吧

 1 public class VolatileTest {
 2     boolean b = false;
 3     int a = 0;
 4 
 5     public static void main(String[] args) {
 6         for (int i=0; i<1000000; i++) {
 7             VolatileTest resource = new VolatileTest();
 8             Thread t1 = new Thread(new A(resource));
 9             Thread t2 = new Thread(new B(resource));
10             t1.start();
11             t2.start();
12             //System.out.println(i);
13         }
14     }
15 }
16 
17 class A implements Runnable {
18     VolatileTest r = null;
19 
20     public A(VolatileTest a) {
21         r = a;
22     }
23 
24     public void run() {
25         r.a = 1;
26         r.b = true;
27     }
28 
29 }
30 
31 class B implements Runnable {
32     VolatileTest r = null;
33 
34     public B(VolatileTest a) {
35         r = a;
36     }
37 
38     public void run() {
39         while (!r.b) {
40             Thread.yield();
41         }
42         int temp = r.a;
43         if (temp == 0) {
44             System.out.println("出现CPU指令重排");
45         }
46     }
47 }

在这个例子中我总共输出了11次出现CPU指令重排

之所以会有这个输出,是因为虽然在A类里代码是先将r.a设置为1,再修改r.b为true.(Line:25,26)但是在CPU执行的时候仍然可能会先做第26行代码,再做25行代码..因为这2行代码之间没有什么关联.所以优化的时候可能会改变顺序.这样就导致了会输出出现CPU指令重排

如果将VolatileTest 的b属性增加volatile关键字的话就不会有这个情况.它可以保证这个对象前面的操作与后面的操作的顺序不会相互调换.相当于把原本代码分成了2段(A类的run方法中25行之前的代码是一段,25行之后的代码是一段,只是这里run里的代码比较少),前后2段代码顺序不会调换,但是这2段代码自己内部之间的顺序还是可以调换的.

这种问题在单线程下是不会出现的,因为如果前后2句代码之间有关联,那么CPU会保证前一句代码先于后一句代码执行.但是在多线程里得不到保证. 所以才需要volatile关键字

我现在对volatile的理解就是它像是synchronized的弱化版本.它可以阻止一些情况下的并发问题,但是另外一些情况的并发问题是阻止不了的.(后面会写哪些情况可以哪些不可以)

posted @ 2016-01-15 11:30  abcwt112  阅读(204)  评论(0编辑  收藏  举报