java并发,操作i++,一个诡异的问题!

问题描述

源代码public class Test { public static void main(String[] args) { final TestRun run = new TestRun(); Thread thread = new Thread(run); Thread thread2 = new Thread(run); thread.start(); thread2.start(); }}class TestRun implements Runnable { public Integer i = 0; public Object lock = new Object(); @Override public void run() { synchronized (i) { i++; System.out.println("step1:" + i); i++; System.out.println("step2:" + i); } }}运行的结果。按理说,锁住了i对象,同步快中的内容顺序执行,结果为:step1:1step2:2step1:3step2:4但结果却是:step1:1step1:2step2:3step2:4或者step1:1step2:3step1:2step2:4貌似没有锁住。当改为synchronized (lock){ ……}结果就正常了!为什么????锁住对象了,不能对对象进行操作吗? 问题补充:liuqing_2010_07 写道

解决方案

原因是Java的自动封箱和解箱操作在作怪。这里的i++实际上是i = new Integer(i+1),所以执行完i++后,i已经不是原来的对象了,同步块自然就无效了。其它基本类型的封装类,如Short、Long等等也不能作为同步对象
解决方案二:
小哀同学 已经道出天机。通过反编译代码来看这个问题。// Decompiled by DJ v2.9.9.60 Copyright 2000 Atanas Neshkov Date: 2012-4-5 13:09:35// Home Page : http://members.fortunecity.com/neshkov/dj.html - Check often for new version!// Decompiler options: packimports(3) // Source File Name: Airplane.javapackage test;import java.io.PrintStream;class TestRun implements Runnable{ TestRun() { i = Integer.valueOf(0); lock = new Object(); } public void run() { synchronized(i) { i = Integer.valueOf(i.intValue() + 1); System.out.println((new StringBuilder("step1:")).append(i).toString()); i = Integer.valueOf(i.intValue() + 1); System.out.println((new StringBuilder("step2:")).append(i).toString()); } } public Integer i; public Object lock;}i = Integer.valueOf(i.intValue() + 1);在这里i已经变为新的对象。所以当线程2进入时临界区的对象i为新的没有加锁的对。所以线程2能够闯入。加锁失败。在这里这种加锁方法本身就是不好的。直接用lock就行了。你可以Integer ii = new Integer (0);synchronized(i)像上面那样也是没有问题的。你遇到的这种现象属于“临界区资源泄漏”。
解决方案三:
加锁失败。

时间: 2024-10-31 22:14:02

java并发,操作i++,一个诡异的问题!的相关文章

c#写怎么防止并发操作(一个要删文件,一个要读文件)?

问题描述 c#写怎么防止并发操作(一个要删文件,一个要读文件)? c#写web后台文件和数据库操作,怎么防止并发操作(一个要删文件,一个要读文件)? 解决方案 你读文件的时候指定FileShare.Read,你删除的时候就会收到一个异常,不允许删除. 你在读文件的时候除非读完,不要Close文件,就可以了. https://msdn.microsoft.com/zh-cn/library/system.io.fileshare(VS.80).aspx

二进制-新手请教java文件操作的一个小问题~十分感谢

问题描述 新手请教java文件操作的一个小问题~十分感谢 这个类的功能是将任意一个二进制文件中的0压缩成0的数目+0的形式 即:将二进制文件中16进制显示的00压缩成 "0的数目+00的形式" 如00 00 00 1A 压缩成03 00 1A 待压缩文件16进制内容: 代码执行后后生成的文件却成了如图所示的情况 求教什么地方出错了,万分感谢. import java.io.*; public class FileCompression { public static void main

jsp 网站开发-JAVA WEB应用,一个操作只能同时有一个用户操作

问题描述 JAVA WEB应用,一个操作只能同时有一个用户操作 一个B/S系统,其中有个调用Linux脚本的操作,执行时间较长,要求系统只能同时有一个用户执行此操作,否则提示其他用户正在执行,请问下该如何实现呢? 解决方案 在該腳本開頭添加"ps -ef | grep 'yourshell'",返回監測結果,看是繼續執行,或是退出交回到java 解决方案二: 这个可以当启动linux脚本时写一个标识位到一个文件内.当其它用户再启动linux脚本时检测这个文件.是否存在即可. 解决方案三

书籍中的一个小样章-Java并发编程AQS原理浅析

AQS的全称为(AbstractQueuedSynchronizer),这个类也是在java.util.concurrent.locks下面.这个类似乎很不容易看懂,因为它仅仅是提供了一系列公共的方法,让子类来调用.那么要理解意思,就得从子类下手,反过来看才容易看懂.如下图所示: 图 5-15 AQS的子类实现 这么多类,我们看那一个?刚刚提到过锁(Lock),我们就从锁开始吧.这里就先以ReentrantLock排它锁为例开始展开讲解如何利用AQS的,然后再简单介绍读写锁的要点(读写锁本身的实

JAVA并发编程学习笔记之CAS操作

CAS操作 CAS是单词compare and set的缩写,意思是指在set之前先比较该值有没有变化,只有在没变的情况下才对其赋值. 我们常常做这样的操作 if(a==b) { a++; } 试想一下如果在做a++之前a的值被改变了怎么办?a++还执行吗?出现该问题的原因是在多线程环境下,a的值处于一种不定的状态.采用锁可以解决此类问题,但CAS也可以解决,而且可以不加锁. int expect = a; if(a.compareAndSet(expect,a+1)) { doSomeThin

请教前辈们java文件操作小生的一个疑惑

问题描述 请教前辈们java文件操作小生的一个疑惑 不明白为什么程序执行后temp和二进制值对应不上,且到循环第四次是没有输出temp=0执行了 这是待处理文件的16进制代码 这是输出 import java.io.*; public class test1 { public static void main(String args[]) throws Exception { FCompression(); } public static void FCompression()throws Ex

模拟Ping操作的一个Java类_java

本文为大家分享了模拟Ping操作的一个Java类,具体内容如下 import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; /** * Created by QiuJU * on 2014/9/21. */ public class SimplePing implements Runnable { private final Object mEndLock = new

Java并发集合的实现原理

本文简要介绍Java并发编程方面常用的类和集合,并介绍下其实现原理. AtomicInteger 可以用原子方式更新int值.类 AtomicBoolean.AtomicInteger.AtomicLong 和 AtomicReference 的实例各自提供对相应类型单个变量的访问和更新.基本的原理都是使用CAS操作: boolean compareAndSet(expectedValue, updateValue); 如果此方法(在不同的类间参数类型也不同)当前保持expectedValue,

如何使用Contemplate ThreadSafe发现并判断Java并发问题

事实证明,要发挥多核硬件所带来的收益是很困难和有风险的.当使用并发正确和安全地编写Java软件时,我们需要很仔细地进行思考.因为错误使用并发会导致偶尔才出现的缺陷,这些缺陷甚至能够躲过最严格的测试环境. 静态分析工具提供了一种方式,可以在代码执行之前探查并修正并发错误.它能够在代码执行之前分析程序的源码或编译形成的字节码,进而发现隐藏在代码之中的缺陷. Contemplate的ThreadSafe Solo是一个商用的Eclipse静态分析插件,其目的就是专门用来发现并诊断隐藏在Java程序之中

Java并发基础实践:退出任务I

计划写一个"Java并发基础实践"系列,算作本人对Java并发学习与实践的简单总结.本文是该系列的第一篇,介绍了退出并发任务的最简单方法. 在一个并发任务被启动之后,不要期望它总是会执行完成.由于时间限制,资源限制,用户操作,甚至是任务中的异常(尤其是运行时异常),...都可能造成任务不能执行完成.如何恰当地退出任务是一个很常见的问题,而且实现方法也不一而足. 1. 任务 创建一个并发任务,递归地获取指定目录下的所有子目录与文件的绝对路径,最后再将这些路径信息保存到一个文件中,如代码清