博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
多线程之volatile关键字
阅读量:5804 次
发布时间:2019-06-18

本文共 1678 字,大约阅读时间需要 5 分钟。

每个线程都运行在java栈内存中,每个线程都有自己的工作内存。线程的计算一般是通过工作内存进行交互的。如图所示:
从上图中我们可以看到,线程在初始化时从主内存中加载所需的变量值到工作内存中,然后在线程运行时,如果是读取,则直接从工作内存中读取,如果是写入则先写到工作内存中,之后再刷新到主内存中,这个可以看做是JVM的一个简单的内存模型,但是这样的结构在多线程的情况下有可能会出问题。比如:A线程修改变量的值,也刷新到主内存中了,但是此时B、C线程读取的还是本线程的工作内存,也就是它们读取的不是最新的值,此时就会出现不同线程持有的公共资源不同步的情况。
对于此类问题:我们可以使用synchronized关键字来同步代码块,也可以使用Lock锁来解决该问题,不过Java可以使用volatile关键字更简单的解决此类问题。比如在一个变量前加上volatile关键字。。可以确保每个线程对本地变量的访问和修改都是直接与主内存交互的,而不是与本线程的工作内存交互的。保证每个线程都能获得最“新鲜”的变量值。如下图所示:
但是此时我们需要注意的是:volatile变量只能保证线程取的是最新的值,但是并不能保证数据的同步性。两个线程同时修改一个volatile,有可能会产生脏数据。请看代码的例子:
package com.zkn.newlearn.thread;/** * Created by wb-zhangkenan on 2016/11/4. */public class ThreadTestVolatile01 {    public static void main(String[] args){        int value = 100;        //控制循环次数        int loops = 0;        //获取线程组        ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();        while(loops < 1000){            //让多线程共享TestVolatile中count值            TestVolatile testVolatile = new TestVolatile();            for(int i=0;i
这段代码的逻辑是这样的:
启动1000个线程,修改共享资源count的值。
休眠15毫秒,让活动线程数变为1(这里有一个Monitor Ctrl Break线程)。
判断实际值和理想值是否一致,如果不一致则此时出现脏数据
我们先来看看自加的操作:count++这句话可以分为两部分,先取出count的值,再执行加1的操作。所以在某两个紧邻的时间片段内可能会出现下面的事情:
1、第一个时间片段:
A线程获得执行机会,因为有关键字volatile修饰,所以它从主内存中获得count的最新值98,记下来的事情又分为两种类型:
如果是单CPU,此时调度器暂停A线程,让出执行几乎给B线程,于是B线程也获得了count的最新值98。
如果是多CPU,此时线程A继续执行,而线程B也同时获得count的最新值98。
2、第二个时间片段:
如果是单CPU,B线程执行完加1动作(原子操作),count的值为99:。由于是volatile类型的变量,所以直接写入主内存,然后A线程继续执行,计算的结果也是99:,重新写入主内存中。
如果是多CPU,A线程执行完加1动作后修改主内存的变量count为99:,线程B执行完毕后也修改住内存中的变量为99:
当这两个时间片执行完毕后,原本期望的结果为100,单运行后的值却为99:,这表示出现了线程不安全的情况,这也证明了,volatile关键字并不能保证线程安全,它只是能保证当线程需要该变量的值时能够获取到最新的值,不能保证多个线程修改的安全性。
参考自:编写高质量代码 改善Java程序的151个建议。
你可能感兴趣的文章
[转]CNN目标检测(一):Faster RCNN详解
查看>>
NYOJ_214_单调递增子序列(二)
查看>>
数字三角形系列
查看>>
自动化测试时Ios设备无法调出键盘问题
查看>>
android将asseet当中的数据库文件拷到程序目录
查看>>
USACO 1.4.1 Packing Rectangles
查看>>
iOS多线程编程Part 2/3 - NSOperation
查看>>
python学习笔记 Day4
查看>>
【Scheme归纳】3 比较do, let, loop
查看>>
选择排序java代码
查看>>
iOS - 抖音效果
查看>>
【Android】18.1 利用安卓内置的定位服务实现位置跟踪
查看>>
SAP打印机配置
查看>>
js下拉框-3
查看>>
qtp:操作mysql数据库时,提示"str open sql.conn对象打开时,不允许操作的解决方法...
查看>>
Chapter 8. 面向对象(继承)
查看>>
【java】简单实现数据库连接池
查看>>
[BZOJ 4563][Haoi2016]放棋子(错排公式)
查看>>
hdu1408
查看>>
腾讯一shell试题.
查看>>