场景描述:多线程输出1到100,对静态Integer对象加锁,synchronized代码块中操作Integer对象,发生线程安全问题(数据重复)

代码:

public class MyRunnableTest implements Runnable {
public static Integer i = new Integer(0); @Override
public void run() {
while(true){
synchronized (i) {
if(i<100){
i++;
System.out.println(Thread.currentThread()+"i = " + i);
}else {
break;
}
}
}
} public static void main(String[] args) {
Thread t1 = new Thread(new MyRunnableTest());
Thread t2 = new Thread(new MyRunnableTest());
t1.start();
t2.start();
} }

运行结果:

Thread[Thread-0,5,main]i = 1
Thread[Thread-1,5,main]i = 3
Thread[Thread-1,5,main]i = 4
Thread[Thread-1,5,main]i = 5
Thread[Thread-1,5,main]i = 6
Thread[Thread-0,5,main]i = 5
Thread[Thread-1,5,main]i = 7
Thread[Thread-0,5,main]i = 8
Thread[Thread-1,5,main]i = 9
Thread[Thread-0,5,main]i = 10
Thread[Thread-1,5,main]i = 11
Thread[Thread-0,5,main]i = 12
Thread[Thread-1,5,main]i = 13

 

从运行结果中可以发现发生了线程安全问题,为什么呢?为什么synchronized无效了。

我的排查思路:

1、因为没有进行任何的额外操作,所以首先定位问题在i++处

通过javap分析字节码命令,总结:

可以看出:i++的实际操作为:Integer.valueOf(Integer.intValue(i)+1)

我们在看看Integer中vauleOf的源码:

public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
} cache[]数组初始化: 
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);

其中low为-128,hight为127。可以了解到,当i的值为-128~127时,是从IntegerCache中取的(可以理解为从缓存中取的),超过部分是new出来的对象。

2、目前我们慢慢开始解开了问题的面纱,每当i发生自增后,所对象改变了,这里我们还需要清楚一下,synchronized在锁对象发生改变时(测试发现,引用类型对象的内在属性变化不会释放锁)会立即释放锁。所以这里就会出现线程安全问题,而且在单核的运行环境下,所有的线程是并发执行而不是并行执行,当我们运行到system.out.println时,锁已经释放了,假如这边t1线程(当前运行的线程,i=1的情况)释放CPU资源,t2执行,这时i等于2(i++之前),当执行到system.out.println时释放cpu资源(此时i=3),t1执行,i此时已经为3了,所以输出3,在释放cpu资源,t2执行,输出3,这时出现了输出重复值的情况。

synchronized 加锁Integer对象(数据重复)详解的更多相关文章

  1. ContentProvider数据访问详解

    ContentProvider数据访问详解 Android官方指出的数据存储方式总共有五种:Shared Preferences.网络存储.文件存储.外储存储.SQLite,这些存储方式一般都只是在一 ...

  2. 【转载】图说C++对象模型:对象内存布局详解

    原文: 图说C++对象模型:对象内存布局详解 正文 回到顶部 0.前言 文章较长,而且内容相对来说比较枯燥,希望对C++对象的内存布局.虚表指针.虚基类指针等有深入了解的朋友可以慢慢看.本文的结论都在 ...

  3. Scala 深入浅出实战经典 第64讲:Scala中隐式对象代码实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  4. 【HANA系列】SAP HANA XS使用JavaScript数据交互详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA XS使用Jav ...

  5. JVM 运行时数据区详解

    一.运行时数据区 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同数据区域. 1.有一些是随虚拟机的启动而创建,随虚拟机的退出而销毁,所有的线程共享这些数据区. 2.第二种则 ...

  6. 【HANA系列】【第一篇】SAP HANA XS使用JavaScript数据交互详解

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列][第一篇]SAP HANA XS ...

  7. CEPH-4:ceph RadowGW对象存储功能详解

    ceph RadosGW对象存储使用详解 一个完整的ceph集群,可以提供块存储.文件系统和对象存储. 本节主要介绍对象存储RadosGw功能如何灵活的使用,集群背景: $ ceph -s clust ...

  8. Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解

    Jquery遍历筛选数组的几种方法和遍历解析json对象|Map()方法详解 一.Jquery遍历筛选数组 1.jquery grep()筛选遍历数组 $().ready( function(){ v ...

  9. java使用POI操作XWPFDocument中的XWPFRun(文本)对象的属性详解

    java使用POI操作XWPFDocument中的XWPFRun(文本)对象的属性详解 我用的是office word 2016版 XWPFRun是XWPFDocument中的一段文本对象(就是一段文 ...

随机推荐

  1. Heavy Cargo POJ 2263 (Floyd传递闭包)

    Description Big Johnsson Trucks Inc. is a company specialized in manufacturing big trucks. Their lat ...

  2. 【Alpha】阶段第五次Scrum Meeting

    [Alpha]阶段第五次Scrum Meeting 工作情况 团队成员 今日已完成任务 明日待完成任务 刘峻辰 增加课程接口 增加教师接口 赵智源 整合前端进行部署 构建后端测试点测试框架 肖萌威 编 ...

  3. Python:Python的运行过程

    1.Python是什么 和Java以及c#一样,Python也是一门基于虚拟机的语言.熟悉Java开发的人在命令行执行一个Java程序的过程通常如下: javac hello.java java he ...

  4. struts2--文件上传类型3

    拦截器栈在<package>标签内 <action>标签外配置 如上我们如果把它定义成默认拦截器的话就不需要在 <action>标签中引入,没有的话需要引入拦截器 ...

  5. HDU 5207 Greatest Greatest Common Divisor

    题目链接: hdu:http://acm.hust.edu.cn/vjudge/problem/visitOriginUrl.action?id=153598 bc(中文):http://bestco ...

  6. HDU 2164 Rock, Paper, or Scissors?

    http://acm.hdu.edu.cn/showproblem.php?pid=2164 Problem Description Rock, Paper, Scissors is a two pl ...

  7. script 执行的三种方式

    <script>: 脚本的获取和执行是同步的.此过程中页面被阻塞,停止解析. <script defer = "defer">:脚本的获取是异步的,执行是同 ...

  8. 知识点总结:Linq和Lambda

    基本语法: Linq:var result=from t in table order by sort ascending/descending select t: Lambda:var result ...

  9. 【C++】为多态基类声明virtual析构函数

    来自<Effective C++>条款07:为多态声明virtual析构函数 当derived class对象经由一个base class指针被删除,而该base class带着一个non ...

  10. 【移动端debug-2】Flexbox在移动端的兼容实践

    最近在项目中用到了flexbox,总结一下使用心得. 一.什么是flexbox,干嘛使的? 曾几何时,我们特别希望能像word一样,在排版时有个分散对齐选项(平均分配子元素宽度)这样我就可以任意在父元 ...