专栏首页Jerry的SAP技术分享一个具体的例子学习Java volatile关键字
原创

一个具体的例子学习Java volatile关键字

相信大多数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的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 一个具体的例子学习Java volatile关键字

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

    Jerry Wang
  • SAP官方发布的ABAP编程规范

    版权声明:署名,允许他人基于本文进行创作,且必须基于与原先许可协议相同的许可协议分发本文 (Creative Commons)

    Jerry Wang
  • 在ABAP里模拟实现Java Spring的依赖注入

    Dependency Injection- 依赖注入,在Java Spring框架中有着广泛地应用。通过依赖注入,我们不必在应用代码里繁琐地初始化依赖的资源,非...

    Jerry Wang
  • 一个具体的例子学习Java volatile关键字

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

    Jerry Wang
  • 简述JVM基础(七):Java 内存模型与线程

    由于在进行运算时如果直接操作内存效率会比较低,用CPU又比较消耗资源,所以在中间加了一层高速缓存区,作为内存和处理器之间的缓存。进行运算时可以先在高速缓存区进行...

    open
  • 浅析java内存模型--JMM

    在并发编程中,多个线程之间采取什么机制进行通信(信息交换),什么机制进行数据的同步?

    烂猪皮
  • 谁说深入浅出虚拟机难?现在我让他通俗易懂(JVM)

    1:什么是JVM 大家可以想想,JVM 是什么?JVM是用来干什么的?在这里我列出了三个概念,第一个是JVM,第二个是JDK,第三个是JRE。相信大家对这三个不...

    吴生
  • java中的内存模型

    现在是资源共享的时代,同样也是知识分享的时代,如果你觉得本文能学到知识,请把知识与别人分享。

    互扯程序
  • Java虚拟机--内存模型

    SuperHeroes
  • Java内存模型

    在多核时代,如何提高CPU的性能成为了一个永恒的话题,而这个话题的讨论主要就是如何定义一个高性能的内存模型,内存模型用于定义处理器的各层缓存与共享内存的同步机制...

    用户1263954

扫码关注云+社区

领取腾讯云代金券