相信大多数Java程序员都学习过volatile这个关键字的用法。百度百科上对volatile的定义:

volatile是一个类型修饰符(type specifier),被设计用来修饰被不同线程访问和修改的变量。volatile的作用是作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。

可能有很多刚学Java的朋友们看了上面这段非常笼统的描述后仍然觉得云里雾里的。

下面我们就用一个具体的例子来学习volatile的用法。

看这个例子:

public class ThreadVerify {
public static Boolean stop = false;
public static void main(String args[]) throws InterruptedException {
Thread testThread = new Thread(){
@Override
public void run(){
int i = 1;
while(!stop){
//System.out.println("in thread: " + Thread.currentThread() + " i: " + i);
i++;
}
System.out.println("Thread stop i="+ i);
}
}
;
testThread.start();
Thread.sleep(1000);
stop = true;
System.out.println("now, in main thread stop is: " + stop);
testThread.join();
}
}

这段代码在主线程的第二行定义了一个布尔变量stop, 然后主线程启动一个新线程,在线程里不停得增加计数器i的值,直到主线程的布尔变量stop被主线程置为true才结束循环。

主线程用Thread.sleep停顿1秒后将布尔值stop置为true。

因此,我们期望的结果是,上述Java代码执行1秒钟后停止,并且打印出1秒钟内计数器i的实际值。

然而,执行这个Java应用后,你发现它进入了死循环,在任务管理器里发现这个Java程序CPU占用率飙升。

原因是什么呢?让我们温习下计算机专业课操作系统中讲过的内存模型的知识。

以Java内存模型为例,Java内存模型分为主内存(main memory)和工作内存(work memory)。主内存内的变量由所有线程共享,每个线程拥有自己的工作内存,里面的变量包含了线程局部变量。主内存中的变量如果被线程使用到,则线程的工作内存会维护一份主内存变量的副本拷贝。

线程对变量的所有读写操作必须在工作内存中进行,不能直接操作主内存中的变量。不同线程之间也无法直接访问对方的工作内存。线程间变量的传递需通过主内存来完成。线程、主内存、工作内存三者之间的交互关系如下图:

如果线程在自己的执行代码里修改了定义在主线程(主内存)中的变量,修改直接发生在线程的工作内存里,然后在某个时刻(Java程序员无法控制这个时刻,而是由JVM调度的),这个修改从工作内存写回到主内存。

回到我们的例子。尽管主线程修改了stop变量,但是仅仅修改了主内存中的值,而操作计数器的线程的工作内存里的stop变量还是旧的值,始终为false。因此这个线程陷入了死循环。

知道了原理,解决方案就很简单了。在stop变量前加上关键字volatile进行修饰,这样在计数器线程里每次读取stop的值时,volatile会强制该线程从主内存读取,而不是从当前线程的工作内存读取。这样就避免了死循环。下图显示1秒钟之后,计数器执行了14亿次。

要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

一个具体的例子学习Java volatile关键字的更多相关文章

  1. [Java并发编程(三)] Java volatile 关键字介绍

    [Java并发编程(三)] Java volatile 关键字介绍 摘要 Java volatile 关键字是用来标记 Java 变量,并表示变量 "存储于主内存中" .更准确的说 ...

  2. 13、Java并发性和多线程-Java Volatile关键字

    以下内容转自http://tutorials.jenkov.com/java-concurrency/volatile.html(使用谷歌翻译): Java volatile关键字用于将Java变量标 ...

  3. Java Volatile关键字(转)

    出处:  Java Volatile关键字 Java的volatile关键字用于标记一个变量“应当存储在主存”.更确切地说,每次读取volatile变量,都应该从主存读取,而不是从CPU缓存读取.每次 ...

  4. Java volatile 关键字底层实现原理解析

    本文转载自Java volatile 关键字底层实现原理解析 导语 在Java多线程并发编程中,volatile关键词扮演着重要角色,它是轻量级的synchronized,在多处理器开发中保证了共享变 ...

  5. Java volatile关键字详解

    Java volatile关键字详解 volatile是java中的一个关键字,用于修饰变量.被此关键修饰的变量可以禁止对此变量操作的指令进行重排,还有保持内存的可见性. 简言之它的作用就是: 禁止指 ...

  6. java线程学习之volatile关键字

    volatile变量的主要作用:是使变量在多个线程间可见. 在java中每一个线程都会有一块工作内存区,其中存放着所有线程共享的主内存的变量值的拷贝.当线程执行时,它在自己的工作内存区操作这些变量,为 ...

  7. Java并发编程学习:volatile关键字解析

    转载:https://www.cnblogs.com/dolphin0520/p/3920373.html 写的非常棒,好东西要分享一下 Java并发编程:volatile关键字解析 volatile ...

  8. 从根源上解析 Java volatile 关键字的实现

    1.解析概览 内存模型的相关概念 并发编程中的三个概念 Java内存模型 深入剖析Volatile关键字 使用volatile关键字的场景 2.内存模型的相关概念 缓存一致性问题.通常称这种被多个线程 ...

  9. java volatile关键字解析

    volatile是什么 volatile在java语言中是一个关键字,用于修饰变量.被volatile修饰的变量后,表示这个变量在不同线程中是共享,编译器与运行时都会注意到这个变量是共享的,因此不会对 ...

随机推荐

  1. Tomcat-redis-Nginx

    环境:centos7, Tomcat7, redis-3.2,Nginx1.8,jdk-8u60-linux-x64 Nginx反向代理tomcat,redis作会话共享 一.Nginx安装 解决依赖 ...

  2. Flutter实战视频-移动电商-61.购物车_商品数量的加减操作

    61.购物车_商品数量的加减操作 provide/cart.dart pages/cart_page/cart_count.dart 先引入provide和cartProvide 定义接收一个item ...

  3. Python及Pycharm安装详细教程

    参考:http://blog.csdn.net/qq_29883591/article/details/52664478 首先我们来安装python 1.首先进入网站下载:点击打开链接(或自己输入网址 ...

  4. sqlserver——视图

    数据库中的视图是一个虚拟表.同真实的表一样,视图包含一系列带有名称的列和行数据,行和列数据用来自由定义视图和查询所引用的表,并且在引用视图时动态产生.本篇将通过一些实例来介绍视图的概念,视图的作用,创 ...

  5. Spring Boot 学习系列(04)—分而治之,多module打包

    此文已由作者易国强授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 明确功能,各司其职 在一个结构清晰的项目中,一个没有module划分的结构显然不是最佳实践.有人会说可以在同 ...

  6. Lightoj1084【DP啊DP】

    题意: 给你n个人的位置,每个人最多移动k个单位,然后在某点>=3人可以抱团,问你这n个人最少抱团数,只要有一个n不能抱团输出-1: 思路: 感觉又是超级超级狗血.... 剪不断,理还乱... ...

  7. HDU 3501【欧拉函数拓展】

    欧拉函数 欧拉函数是指:对于一个正整数n,小于n且和n互质的正整数(包括1)的个数,记作φ(n) . 通式:φ(x)=x*(1-1/p1)(1-1/p2)(1-1/p3)*(1-1/p4)-..(1- ...

  8. css div平移淡入淡出

    <!DOCTYPE html> <html> <head> <style> div { width:100px; height:100px; backg ...

  9. 17..userinfo.txt 文件中存放以下结构:

    alex:alex3714 wusir:123456 meet:meet123 1.让用户选择: 1.注册 2.登录 2.用户选择注册就将账号和密码添加到userinfo.txt中,如果用户名存在就提 ...

  10. java并发编程(一)

    java并发编程(一) 线程基础 在Java代码中,单独创建线程,都需要使用类java.lang.Thread,通常可以通过集成并扩展Thread的run()方法,也可以来创建一个Thread,将一个 ...