java 多线程11:volatile关键字
直接先举一个例子普通的线程实例变量的非可见性:
public class MyThread28 extends Thread
{
private boolean isRunning = true; public boolean isRunning()
{
return isRunning;
} public void setRunning(boolean isRunning)
{
this.isRunning = isRunning;
} public void run()
{
System.out.println("进入run了");
while (isRunning == true){}
System.out.println("线程被停止了");
}
}
public static void main(String[] args)
{
try
{
MyThread28 mt = new MyThread28();
mt.start();
Thread.sleep(1000);
mt.setRunning(false);
System.out.println("已赋值为false");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
看一下运行结果:
进入run了
已赋值为false
也许这个结果有点奇怪,明明isRunning已经设置为false了, 线程还没停止呢?
这就要从Java内存模型(JMM)说起,这里先简单讲,虚拟机那块会详细讲的。根据JMM,Java中有一块主内存,不同的线程有自己的工作内存,同一个变量值在主内存中有一份,如果线程用到了这个变量的话,自己的工作内存中有一份一模一样的拷贝。每次进入线程从主内存中拿到变量值,每次执行完线程将变量从工作内存同步回主内存中。
注意这里的情况只会出现Server模式,Client模式不会出现,而且要先睡一段时间再设置false,估计是为了让子线程read load 好主内存字段吧,不设置睡觉的话,子线程来不及 read load 就会立刻停止了
出现打印结果现象的原因就是主内存和工作内存中数据的不同步造成的。因为执行run()方法的时候拿到一个主内存isRunning的拷贝,而设置isRunning是在main函数中做的,换句话说 ,设置的isRunning设置的是主内存中的isRunning,更新了主内存的isRunning,线程工作内存中的isRunning没有更新,当然一直死循环了,因为对于线程来说,它的isRunning依然是true。
解决这个问题很简单,给isRunning关键字加上volatile。加上了volatile的意思是,每次读取isRunning的值的时候,都先从主内存中把isRunning同步到线程的工作内存中,再当前时刻最新的isRunning。看一下给isRunning加了volatile关键字的运行效果:
进入run了
已赋值为false
线程被停止了
看到这下线程停止了,因为从主内存中读取了最新的isRunning值,线程工作内存中的isRunning变成了false,自然while循环就结束了。
volatile之前的普通线程内存模型

使用 volatile 之后



这里可以参考 java虚拟机9:Java的内存模型
volatile的作用就是这样,被volatile修饰的变量,保证了每次读取到的都是最新的那个值。线程安全围绕的是可见性和原子性这两个特性展开的,volatile解决的是变量在多个线程之间的可见性,但是无法保证原子性。
多提一句,synchronized除了保障了原子性外,其实也保障了可见性。因为synchronized无论是同步的方法还是同步的代码块,都会先把主内存的数据拷贝到工作内存中(synchronized 只要一经线程调用,无所谓你锁的谁,只要跟进程相关的实例变量,静态变量都会同步到主内存,实现可见性,下面可以看到例子),同步代码块结束,会把工作内存中的数据更新到主内存中,这样主内存中的数据一定是最新的。














java 多线程11:volatile关键字的更多相关文章
- Java多线程编程——volatile关键字
(本篇主要内容摘自<Java多线程编程核心技术>) volatile关键字的主要作用是保证线程之间变量的可见性. package com.func; public class RunThr ...
- 【java多线程】volatile 关键字
在java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语 ...
- Java多线程技术-Volatile关键字解析
分析volatile关键字可以从这三个方面分析,什么是程序的原子性,什么是程序的可见性,什么是程序的有序性 什么是程序的原子性 以下语句那些是原子操作? public class ThreadCoun ...
- Java多线程:volatile 关键字
一.内存模型的相关概念 大家都知道,计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入.由于程序运行过程中的临时数据是存放在主存(物理内存)当中的,这时就存 ...
- java 轻量级同步volatile关键字简介与可见性有序性与synchronized区别 多线程中篇(十二)
概念 JMM规范解决了线程安全的问题,主要三个方面:原子性.可见性.有序性,借助于synchronized关键字体现,可以有效地保障线程安全(前提是你正确运用) 之前说过,这三个特性并不一定需要全部同 ...
- Java 并发:volatile 关键字解析
摘要: 在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保 ...
- java并发系列(六)-----Java并发:volatile关键字解析
在 Java 并发编程中,要想使并发程序能够正确地执行,必须要保证三条原则,即:原子性.可见性和有序性.只要有一条原则没有被保证,就有可能会导致程序运行不正确.volatile关键字 被用来保证可见性 ...
- 一起来看看java并发中volatile关键字的神奇之处
并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...
- Java并发编程 Volatile关键字解析
volatile关键字的两层语义 一旦一个共享变量(类的成员变量.类的静态成员变量)被volatile修饰之后,那么就具备了两层语义: 1)保证了不同线程对这个变量进行操作时的可见性,即一个线程修改了 ...
- Java中的volatile关键字的功能
Java中的volatile关键字的功能 volatile是java中的一个类型修饰符.它是被设计用来修饰被不同线程访问和修改的变量.如果不加入volatile,基本上会导致这样的结果:要么无法编写多 ...
随机推荐
- poj 2195 Going Home(最小费最大流)
poj 2195 Going Home Description On a grid map there are n little men and n houses. In each unit time ...
- zabbix 介绍
zabbix实现原理及架构详解想要用好zabbix进行监控,那么我们首要需要了解下zabbix这个软件的实现原理及它的架构.建议多阅读官方文档. 一.总体上zabbix的整体架构如下图所示: 重要组件 ...
- 简单安装MongoDB
前言 首先说明一下环境,以免环境的不同造成不必要的影响 本次采用centos6.8版本linux系统 [root@dev1 ~]# cat /etc/redhat-release CentOS rel ...
- HDUOJ---1102Constructing Roads
Constructing Roads Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Other ...
- HDUOJ --2523
http://acm.hdu.edu.cn/showproblem.php?pid=2523 哈希表..球阀 代码: #include<iostream> #include<vec ...
- Windows下面安装和配置Solr 4.9(一)
1.Solr下载 下载地址 :http://lucene.apache.org/solr/ 2.解压,测试 在example文件夹中找到start.jar文件,用命令提示符运行这个文件:ja ...
- python学习笔记——守护进程
1 基本描述 守护进程:是系统中独立的后台服务进程, 特点:独立与终端并且周期性地执行某个任务,其生命周期长,一般随系统启动和终止. 缺点:进程的创建和销毁的时候需要消耗较多的计算机资源. 2 参考 ...
- Error_Unix Shell_syntax error near unexpected token `fi'
2014-06-19 BaoXinjian 1. Issue 调用如下Shell脚本时出现错误syntax error near unexpected token `fi'
- OkHttp拦截器的实现原理
今天项目中遇到需要将从push接收到的数据按照协议parse成应用层需要的结构化数据类型问题:因为push消息类型繁多,等待解析出的结构化数据类型也多样,有的还需要经过几步的parse过程:而且因为项 ...
- 让thinkphp 支持ftp上传到远程,ftp删除
让thinkphp真正的支持FTP上传.删除. 原创by default7#zbphp.com,如需转载请保留作者信息. /** * This is not a free software, All ...