美文网首页
java多线程随笔笔记

java多线程随笔笔记

作者: wbpailxt | 来源:发表于2019-12-28 14:27 被阅读0次
package jmm;

/**
 * 描述:     演示可见性带来的问题
 */
public class FieldVisibilityMe1 {

    volatile int a = 1;
    volatile int b = 2;
    private void change() {
        a = 3;
        b = a;
    }


    private void print() {
        System.out.println("a=" + a + ";b=" + b);
    }

    public static void main(String[] args) {
        while (true) {
            FieldVisibilityMe1 test = new FieldVisibilityMe1();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    test.change();
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    test.print();
                }
            }).start();
        }
    }
}

结果:

图片.png
分析:
加了volatile关键字之后,依旧会出现a=1;b=3的情况不是volatile关键期不字作用,没有把修改后的值立刻刷新到主内存。而是会出现以下一种情况。
读线程取a的值的时候,依旧是会去主内存拷贝a的值到工作内存,但是由于写线程还没修改a的值,取到的值还是1。当读线程要取b的值的时候,写线程已经完成了b的赋值操作,当读线程取主内存拷贝b的值的时候,拷贝的是修改后的值3。所以就出现了a=1;b=3的情况。
那假如print函数中的System.out.println("a=" + a + ";b=" + b);改成System.out.println("b=" + b + ";a=" + a);呢?
结果是不会出现b=3;a=1的情况了。
由于读线程去主内存拷贝b的值,此时b必然是已经修改后的值,然后再去主内存拷贝a的值,由于a必在b之前修改,所以a必然是已经修改后的值。所以就不会出现b=3;a=1的情况了。
那假如在上述情况下再改变一下,a不是用volatile关键字修饰会怎么样?
结果也是不会出现b=3;a=1的情况了。
由于as-if-series原则保证单线程执行结果的一致性,a=3必在b=a之前执行,再根据happens-before原则的传递性,a=3对b=a可见,b=a对读线程可见,所以a=3对读线程可见。所以就不会出现b=3;a=1的情况了。

相关文章

网友评论

      本文标题:java多线程随笔笔记

      本文链接:https://www.haomeiwen.com/subject/oxdsoctx.html