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;
}
}
}
}
测试执行如下:
3.线程的值变换,不同的线程在内存中不可见
在上面的示例中,我们可以看到主要有两个线程,一个是启动的 thread 线程,和 main 线程。
在 thread 线程中,在休眠200毫秒之后,已经在内存中将 flag 值设置为 true
但是在 main 线程中,由于 while true 没有做任何的延时操作,运行效率非常高,根本不管内存中 flag 值的变换,进行无限的循环。
4.在 while 循环中设置延时 或者 设置线程同步,就可以解决这个 内存不可见 的问题
或者设置线程同步,如下:
5.总结
我们可以将 while(true) 假设快速执行并发的线程, 这种时候也是会存在 内存不可见 的问题。
使用 volatitle 关键字 处理内存不可见的问题
在上面的示例中,我们可以使用 线程延时 或者 synchronized 同步关键字 来解决 内存不可见的问题。
但是这两种解决方式都有一个问题:执行的效率低。
那么有没有居中的解决方式呢?既可以让效率没有那么低,又可以解决 内存不可见的问题的。
下面来看看 volatitle 关键字,如下:
1.在定义线程实现类的成员属性中,设置 volatitle 关键字
2.再次执行测试
原文始发于微信公众号(海洋的渔夫):2.volatile 关键字-内存可见性
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/35016.html