源代码
[code="java"]
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);
}
}
}
[/code]
运行的结果。按理说,锁住了i对象,同步快中的内容顺序执行,结果为:
step1:1
step2:2
step1:3
step2:4
但结果却是:
step1:1
step1:2
step2:3
step2:4
或者
step1:1
step2:3
step1:2
step2:4
貌似没有锁住。
当改为synchronized (lock){
……
}
结果就正常了!
为什么????锁住对象了,不能对对象进行操作吗?
原因是Java的自动封箱和解箱操作在作怪。
这里的i++实际上是i = new Integer(i+1),所以执行完i++后,i已经不是原来的对象了,同步块自然就无效了。
其它基本类型的封装类,如Short、Long等等也不能作为同步对象
加锁失败。
小哀同学 已经道出天机。通过反编译代码来看这个问题。
[code="java"]// 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.java
package 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;
}[/code]
[code="java"]i = Integer.valueOf(i.intValue() + 1);
[/code]
在这里i已经变为新的对象。所以当线程2进入时临界区的对象i为新的没有加锁的对。
所以线程2能够闯入。加锁失败。在这里这种加锁方法本身就是不好的。直接用lock就行了。你可以[code="java"]Integer ii = new Integer (0);
synchronized(i)
[/code]
像上面那样也是没有问题的。
你遇到的这种现象属于“临界区资源泄漏”。