volatile型变量自增操作的隐患
用FindBugs跑自己的项目,报出两处An increment to a volatile field isn’t atomic。对应报错的代码例如以下:
volatile int num = 0;
num++;
FindBugs针对这样的类型的错误给出了对应的解释
An increment to a volatile field isn’t atomic
This code increments a volatile field. Increments of volatile fields aren’t atomic. If more than one thread is incrementing the field at the same time, increments could be lost.
意即,对一个volatile字段进行自增操作。但这个字段不是原子类型的。假设多个线程同一时候对这个字段进行自增操作。可能会丢失数据。
volatile是一个轻量级的synchronized的实现,针对volatile类型变量的操作都是线程安全的。volatile类型变量每次在读取的时候。都从主存中取。而不是从各个线程的“工作内存”。
而非volatile型变量每次被读取的时候都是从线程的工作内存中读取主存中变量的一份拷贝。也就意味着假设非volatile型变量被某个线程改动,其他线程读取的可能是旧值。
jvm内存模型图
volatile类型变量每次在读取的时候,会越过线程的工作内存,直接从主存中读取。也就不会产生脏读。
那为何FindBugs报这个错?
根本原因在于++自增操作。Java的++操作对应汇编指令有三条
1. 从主存读取变量值到cpu寄存器
2. 寄存器里的值+1
3. 寄存器的值写回主存
假设N个线程同一时候运行到了第一步。那么终于变量会损失(N - 1)。第二步第三步仅仅有一个线程是运行成功。
写个demo验证这个问题
package com.alibaba.bop.tag.manager;
import org.junit.Test;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* author : lvsheng
* date : 2016/11/22 下午5:06
*/
public class volatileTest {
volatile int num = 0;
int coreSize = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor exec = new ThreadPoolExecutor(coreSize * 2, coreSize * 3, 0, TimeUnit.SECONDS,
new LinkedBlockingQueue<Runnable>(500), new ThreadPoolExecutor.CallerRunsPolicy());
@Test
public void test() {
for (int i = 0; i < Integer.MAX_VALUE; i++) {
exec.execute(() -> num++);
}
System.out.println(Integer.MAX_VALUE);
System.out.println(num);
System.out.println("误差 : " + (Integer.MAX_VALUE - num));
}
}
运行结果
2147483647
2121572795
误差 :25910852
自增操作整体上产生了1%的误差。FindBugs是个好工具。能找出自己知识体系范围外的bug。surprise!
volatile型变量自增操作的隐患的更多相关文章
- volatile型变量语义讲解一 :对所有线程的可见性
volatile型变量语义讲解一 :对所有线程的可见性 一.volatile变量语义一的概念 当一个变量被定义成volatile之后,具备两个特性: 特性一:保证此变量对所有线程的可见性.这里的&qu ...
- Java虚拟机内存模型和volatile型变量
Java虚拟机内存模型 了解Java虚拟机的内存模型,有助于我们明白为什么会发生线程安全问题. 上面这幅图是<深入理解Java虚拟机-JVM高级特性与最佳实践>的书中截图. 线程共享的变量 ...
- Java线程角度的内存模型和volatile型变量
内存模型的目标是定义程序中各个变量的访问 规则,即在虚拟机中将变量(包括实例字段,静态字段和构成数组对象的元素,不包括局部变量与方法参数,因为后者是线程私有的)存储到内存和从内存中取出变量这样的底层细 ...
- synchronized同步块和volatile同步变量
Java语言包含两种内在的同步机制:同步块(或方法)和 volatile 变量.这两种机制的提出都是为了实现代码线程的安全性.其中 Volatile 变量的同步性较差(但有时它更简单并且开销更低),而 ...
- Programming In Scala笔记-第五章、Scala中的变量类型和操作
这一章的一些基础性的东西,主要包括Scala中的基本变量类型,以及相关的一些操作符. 一.简单类型 下表中列出Scala语言中的基本类型,以及其字节长度,其中Byte, Short, Int, Lon ...
- seaborn 数据可视化(一)连续型变量可视化
一.综述 Seaborn其实是在matplotlib的基础上进行了更高级的API封装,从而使得作图更加容易,图像也更加美观,本文基于seaborn官方API还有自己的一些理解. 1.1.样式控制: ...
- Java-JUC(十三):现在有两个线程同时操作一个整数I,做自增操作,如何实现I的线程安全性?
问题分析:正如i在多线程中如果想实现i的多线程操作,必须i要使用volitle来保证其内存可见性,但是i++自增操作不具备原子性操作,因此需要对i++这段代码确保其原子性操作即可. 方案1: 使用Re ...
- bool型变量下标的时候javascript是不能允许的
jother编码是我最开始想写的内容,原因有两点:1.原理比较简单,不需要太多关于算法的知识.2.比较有趣,是在对javascript有了很深的理解之后催生的产物.如果你只需要知道jother编码和解 ...
- (转)C语言16进制输出字符型变量问题
最近在做一个C的嵌入式项目,发现在C语言中用printf()函数打印字符型变量时,如果想采用"%x"的格式将字符型变量值以十六进制形式打印出来,会出现一个小问题,如下: char ...
随机推荐
- iOS推送原理和证书生成简介
1. 推送流程: Provider: 我们自己的后台服务器: APNS: 苹果的消息推送服务器 (1) 当Provider有消息要推送给手机的时候,先将消息和deviceToken等字段发送到APNS ...
- 【 Zabbix 】nginx监控及故障重启服务
zabbix agentd 端配置: nginx.conf 配置: location /ngx_status { stub_status on; access_log off; allow 10.0. ...
- 【 总结 】crontab 使用脚本及直接获取HTTP状态码
一.在crontab里面计划执行的脚本,所有的命令都要写出绝对路径.因为crontab的独立的进程,可能无法直接加载环境变量. 二.在判断网站能否正常访问一般的思路: 1. 判断网站是否能够正常打开. ...
- ie 下input光标位置垂直不居中问题
input输入框用一个背景图模拟,设置height和line-height一样的高度,使里面的输入文字能够居中, 在FF下出现的情况是:点击input时,输入光标其实上跟input的height一样高 ...
- xshell连接虚拟机CentOS出现eth0 device not found的解决方法
昨天用xshell连接虚拟机上的centOS老是连接不上,ifconfig eth0 命令显示 device not found.不知道是什么原因... 折腾了好久 网上是各种搜啊 终于找到解决方法了 ...
- hdu 1423(LCS+LIS)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1423 好坑啊..还有公共串为0时的特殊判断,还有格式错误..看Discuss看知道除了最后一组测试数据 ...
- 云平台资源挂盘办法V1.2
一.优先使用mount 方式进行挂盘,记得使用sync参数,如果对方网络限制了445端口,我们被迫采用第二种办法. mount -t cifs -o sync,username='Administra ...
- 洛谷 P3383 【模板】线性筛素数-线性筛素数(欧拉筛素数)O(n)基础题贴个板子备忘
P3383 [模板]线性筛素数 题目描述 如题,给定一个范围N,你需要处理M个某数字是否为质数的询问(每个数字均在范围1-N内) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示查询的范 ...
- (寒假GYM开黑)2018 German Collegiate Programming Contest (GCPC 18)
layout: post title: 2018 German Collegiate Programming Contest (GCPC 18) author: "luowentaoaa&q ...
- ( 转 ) UML 类图
在UML类图中,常见的有以下几种关系:泛化(Generalization), 实现(Realization),关联(Association),聚合(Aggregation),组合(Compositi ...