Java 层面保证内存可见性的方式

Java 层面保证内存可见性的方式有很多:

1. volatile,用volatile基本数据类型,可以保证每次CPU去操作数据时,都直接去主内存进行读写。

2. synchronized,synchronized的内存语义可以保证在获取锁之后,可以保证前面操作的数据是可见的。

3. lock(CAS-volatile),也可以保证CAS或者操作volatile的变量之后,可以保证前面操作的数据是可见的。

4. final,是常量没法动。

代码示例

public class VisibilityDemo {

    static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (flag) {
                
            }
            System.out.println("t1结束!");
        }).start();

        Thread.sleep(10);
        flag = false;
    }
}

运行结果:t1 没法正常结束.....

volatile 保证内存可见性

public class VisibilityDemo {

    static volatile boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (flag) {

            }
            System.out.println("t1结束!");
        }).start();

        Thread.sleep(10);
        flag = false;
    }
}

运行结果:t1结束!

synchronized 的方式

public class VisibilityDemo {

    static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (flag) {
                synchronized (VisibilityDemo.class) {

                }
            }
            System.out.println("t1结束!");
        }).start();

        Thread.sleep(10);
        flag = false;
    }
}

运行结果:t1结束!

lock 的方式

public class VisibilityDemo {

    static ReentrantLock lock = new ReentrantLock();
    static boolean flag = true;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            while (flag) {
                lock.lock();
                lock.unlock();
            }
            System.out.println("t1结束!");
        }).start();

        Thread.sleep(10);
        flag = false;
    }
}

运行结果:t1结束!

volatile 修饰引用数据类型

结论:volatile修饰引用数据类型,只能保证引用数据类型的地址是可见的,不保证内部属性可见

public class VolatileDemo {

    static class A {

        boolean b = true;

        void run() {
            while (b) {

            }
            System.out.println("A end");
        }
    }

    static volatile A a = new A();

    public static void main(String[] args) throws InterruptedException {
        new Thread(a::run).start();

        Thread.sleep(10);

        a.b = false;
    }
}

运行结果:A 不会结束....

这个结论只能在hotspot中实现,如果换一个版本的虚拟机,可能效果就不一样了。volatile修饰引用数据类型,JVM压根就没规范过这种操作,不同的虚拟机厂商,可以自己实现。

你可能感兴趣的:(java,java,开发语言)