2.volatile 关键字-内存可见性

2.volatile 关键字-内存可见性

前言

在多线程并发中,常常存在多个线程同时操作一个共享属性的情况。而这种情况通常会带来一个 内存可见性 的问题。那么本篇章来介绍一下这个问题,并且讲述一下该如何解决。

知识点说明

内存可见性

- 内存可见性(Memory Visibility)是指当某个线程正在使用对象状态而另一个线程在同时修改该状态,需要确保当一个线程修改了对象状态后,其他线程能够看到发生的状态变化。
- 可见性错误是指当读操作与写操作在不同的线程中执行时,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。
- 我们可以通过同步来保证对象被安全地发布。除此之外我们也可以使用一种更加轻量级的 volatile 变量。

volatile 关键字

Java 提供了一种稍弱的同步机制,即 volatile 变量,用来确保将变量的更新操作通知到其他线程。可以将 volatile 看做一个轻量级的锁,但是又与锁有些不同:
- 对于多线程,不是一种互斥关系
- 不能保证变量状态的“原子性操作”

内存不可见的代码演示

下面我们编写一个线程共享值的示例,演示一下内存不可见的问题。

1.编写一个Runnable线程实现类

//编写Runnable线程类
class ThreadDemo implements Runnable{

    //成员属性
    private boolean flag = false;

    //重写run
    @Override
    public void run() {

        //休眠200毫秒
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        //设置flag为true
        setFlag(true);
        //输出当前flag的值
        System.out.println("flag = " + isFlag());

    }

    // getter setter
    public boolean isFlag() {
        return flag;
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }


}

在 run 方法中可以看到,在上面的线程中,只要休眠 200 毫秒,那么就会立即设置 flag 为 true,并且打印 flag 的值。

2.编写一个 main 测试线程,在线程的下方写一个循环,当发现线程的 flag 值为 true 则中断循环

public class TestVolatile {

    public static void main(String[] args) {
        //1.创建线程实现对象
        ThreadDemo thread = new ThreadDemo();

        //2.创建线程,以及启动线程
        new Thread(thread).start();

        //3.如果flag为true,那么循环就应该中断
        while (true){
            if (thread.isFlag()){
                System.out.println("----------");
                break;
            }
        }

    }

}

测试执行如下:

2.volatile 关键字-内存可见性
image-20201030081607792

3.线程的值变换,不同的线程在内存中不可见

在上面的示例中,我们可以看到主要有两个线程,一个是启动的 thread 线程,和 main 线程。

在 thread 线程中,在休眠200毫秒之后,已经在内存中将 flag 值设置为 true

但是在 main 线程中,由于 while true 没有做任何的延时操作,运行效率非常高,根本不管内存中 flag 值的变换,进行无限的循环。

4.在 while 循环中设置延时 或者 设置线程同步,就可以解决这个 内存不可见 的问题

2.volatile 关键字-内存可见性
image-20201030082751812

或者设置线程同步,如下:

2.volatile 关键字-内存可见性
image-20201030082925121

5.总结

2.volatile 关键字-内存可见性
image-20201030083648419

我们可以将 while(true) 假设快速执行并发的线程, 这种时候也是会存在 内存不可见 的问题。

使用 volatitle 关键字 处理内存不可见的问题

在上面的示例中,我们可以使用 线程延时 或者 synchronized 同步关键字 来解决 内存不可见的问题。

但是这两种解决方式都有一个问题:执行的效率低。

那么有没有居中的解决方式呢?既可以让效率没有那么低,又可以解决 内存不可见的问题的。

下面来看看 volatitle 关键字,如下:

1.在定义线程实现类的成员属性中,设置 volatitle 关键字

2.volatile 关键字-内存可见性
image-20201030084502189

2.再次执行测试

2.volatile 关键字-内存可见性
image-20201030084601177


原文始发于微信公众号(海洋的渔夫):2.volatile 关键字-内存可见性

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/35016.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!