问题描述
源代码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)像上面那样也是没有问题的。你遇到的这种现象属于“临界区资源泄漏”。
解决方案三:
加锁失败。