并发编程三大特性-可见性(visibility)

151 阅读1分钟

1. 基本概念

两个线程同时访问他个参数r
当线程T1读取参数r的时候会将r缓存到自己本地
线程T2读取参数r的时候也会将r缓存到自己本地
若是此时T1修改了参数的值
T2读到的r还是之前的值

public class ThreadVisibility {
    private static boolean r = true;

    private static void m (){
        System.out.println("m start");
        while (r) {
            //do something
        }
        System.out.println("m end");
    }

    public static void main(String[] args) {
        new Thread(ThreadVisibility::m,"t1").start();
        sleep(1);
        r = false;
    }

    private static void sleep(int i) {
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

执行结果为

image.png 并不会由于主线程更改了r的值导致子线程t1的r参数改变,从而停止线程

2. 如何解决这个可见性的问题呢

2.1 使用volatile修饰参数r

volatile修饰的参数的每次修改对其他线程都是可见的,每次读的时候都会去主内存读一遍,对参数修改之后,立马就会刷新到主内存。

public class ThreadVisibility {
    private static volatile boolean r = true;

    private static void m (){
        System.out.println("m start");
        while (r) {
            //do something
        }
        System.out.println("m end");
    }

    public static void main(String[] args) {
        new Thread(ThreadVisibility::m,"t1").start();
        sleep(1);
        r = false;
    }

    private static void sleep(int i) {
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

执行结果为:
image.png

2.2 volatile修饰引用类型

只能保证引用本身的可见性,不能保证内部字段的可见性
只需将volatile加到内部字段上就可保证其内部字段的可见性