volatile关键字与内存可见性
前言
首先,我们使用多线程的目的在于提高程序的效率,但是如果使用不当,不仅不能提高效率,反而会使程序的性能更低,因为多线程涉及到线程之间的调度、CPU上下文的切换以及包括线程的创建、销毁和同步等等,开销比单线程大,因此需谨慎使用多线程。
在jdk1.5以后,提供了一个强大的java.util.concurrent包,这个包中提供了大量的应用于线程的工具类。
下面开始介绍volatile关键字和内存可见性,虽然volatile是在jdk1.5之前就有的,但还是想放在这里讲一下。
举例说明
首先,我们先看一段小程序。
package com.ccfdod.juc; public class TestVolatile {
public static void main(String[] args) {
ThreadDemo td = new ThreadDemo();
new Thread(td).start(); while(true) {
if (td.isFlag()) {
System.out.println("--------------");
break;
}
}
}
} class ThreadDemo implements Runnable {
private boolean flag = false; @Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag = " + isFlag());
} public boolean isFlag() {
return flag;
} public void setFlag(boolean flag) {
this.flag = flag;
}
}
程序运行结果:
flag = true
并且程序不会停止。
按理来说,应该会在td线程修改flag值后,主线程会打印出“--------------”,但是为什么没有出现预期效果呢?下面来分析这段程序,涉及到内存可见性问题。
内存可见性问题
当程序运行时,JVM会为每一个执行任务的线程分配一个独立的缓存空间,用于提高效率。
不难理解,程序开始执行时,由于线程td修改flag操作之前,sleep了200ms,td线程和main线程获取到的flag都为false,但为什么td线程将flag改为true后,main线程没有打印出“--------------”呢?原因在于:while(true)是执行效率很高,使得main线程没有时间再次从主存中获取flag的值,因此程序在td线程将flag修改为true后,没有停止运行的原因。其实在while(true)后面稍微延迟一点(比如说,打印一句话),都会使main线程将主存中的flag=true读取。
产生这种情况的原因就在于,两个线程在操作共享数据时,对共享数据的操作是彼此不可见的。
那么为了不让这种问题出现,怎么解决呢?
一、使用synchronized同步锁
while(true) {
synchronized (td) {
if (td.isFlag()) {
System.out.println("--------------");
break;
}
}
}
使用synchronized同步锁能保证数据的及时更新。但是效率太低。
二、使用volatile关键字
当多个线程进行操作共享数据时,可以保证内存中的数据可见。底层原理:内存栅栏。使用volatile关键字修饰时,可理解为对数据的操作都在主存中进行。
private volatile boolean flag = false;
相较于synchronized是一种较为轻量级的同步策略。
注意:
- volatile不具备“互斥性”
- volatile不能保证变量的“原子性”
关于“原子性”的问题将在下一篇博客中讨论。
volatile关键字与内存可见性的更多相关文章
- volatile关键字与内存可见性&原子变量与CAS算法
1 .volatile 关键字:当多个线程进行操作共享数据时, 可以保证内存中的数据可见 2 .原子变量:jdk1.5后java.util.concurrent.atomic 包下提供常用的原子变量 ...
- 详解volatile 关键字与内存可见性
先来看一个例子: public class VolatileTest { public static void main(String[] args) { T ...
- 【JUC系列第一篇】-Volatile关键字及内存可见性
作者:毕来生 微信:878799579 什么是JUC? JUC全称 java.util.concurrent 是在并发编程中很常用的实用工具类 2.Volatile关键字 1.如果一个变量被volat ...
- volatile关键字及内存可见性
先看一段代码: package com.java.juc; public class TestVolatile { public static void main(String[] args) { T ...
- java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)
概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...
- 【Java并发编程】6、volatile关键字解析&内存模型&并发编程中三概念
volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果.在Java 5之后,volatile关键字才得以 ...
- volatile关键字解析&内存模型&并发编程中三概念
原文链接: http://www.cnblogs.com/dolphin0520/p/3920373.html volatile这个关键字可能很多朋友都听说过,或许也都用过.在Java5之前,它是一个 ...
- volotile关键字的内存可见性及重排序
在理解volotile关键字的作用之前,先粗略解释下内存可见性与指令重排序. 1. 内存可见性 Java内存模型规定,对于多个线程共享的变量,存储在主内存当中,每个线程都有自己独立的工作内存,并且线程 ...
- Java并发机制(3)--volatile关键字与内存模型
Java并发编程:volatile关键字解析及内存模型 个人整理自:博客园-海子-http://www.cnblogs.com/dolphin0520/p/3920373.html 1.线程内存模型: ...
随机推荐
- 23种设计模式UML图
- action接收请求参数
一.采用基本类型接收请求参数(get/post)在Action类中定义与请求参数同名的属性,struts2便能接收自动接收请求参数并赋给同名属性. action的代码: public class Pa ...
- [转]C#读写远程共享文件夹
1.在服务器设置一个共享文件夹,在这里我的服务器ip地址是10.200.8.73,共享文件夹名字是share,访问权限,用户名是administrator,密码是11111111. 2.新建一个控制台 ...
- beego——事务处理和命令模式
1.事务处理 ORM 可以简单的进行事务操作. o := NewOrm() err := o.Begin() // 事务处理过程 ... ... // 此过程中的所有使用 o Ormer 对象的查询都 ...
- javascript DOM dindow.docunment对象
一.找到元素: docunment.getElementById("id"):根据id找,最多找一个: var a =docunment.getElementById(&qu ...
- 笔记——Springboot response、ServletOutputStream、图形验证码显示慢
今天遇到一个图形验证码加载很慢的问题,大概耗时有200~500毫秒左右. 根据追踪,图形验证码图片生成耗时0~1毫秒,而response.getOutputStream.write()将图片写入前台页 ...
- Ubuntu16.04安装Appium
准备工作 1.安装Node 下载地址:https://nodejs.org/en/download/ 下载完后解压,设置环境变量 配置Node环境变量$sudo vim /etc/profile 在文 ...
- C#求百分比
public string integralpercentage; integralpercentage = ((double)user.Credits / integralmax).ToString ...
- 通过自动回复机器人学Mybatis:搭建核心架构
imooc视频学习笔记 ----> URL:http://www.imooc.com/learn/154 MessageDao.java package com.imooc.dao; impor ...
- Centos 7 Sublime 安装 package control
1. 修改installed Packages 下的package Control.sublime-package(原文件是个空的文件) 2. 下载channel_v3.json 可放在任何位置并在s ...