日期:2014-05-20  浏览次数:20643 次

为什么 当一个线程在同步块里的时候,另一个线程还可以进入啊?
各位好~~
本人在学习线程的时候碰到一个问题
以下是代码

public class Test implements Runnable{
public static Integer num = 1;
private String name;
public Test(String name){
this.name = name;
}
public void run(){
int i = 0;
try{
while(true){
System.out.println(name + ": outside");
synchronized(num){
System.out.println(name + ": entered");
if(i > 10){
break;
}
i++;
num--;
Thread.sleep(10);
System.out.println(name + ": leaved");
}
}
}catch(Exception exp){
exp.printStackTrace();
}
}

public static void main(String[] args){
Test t1 = new Test("t1");
Test t2 = new Test("t2");
Thread th1 = new Thread(t1);
Thread th2 = new Thread(t2);
th1.start();
th2.start();
}
}

输出结果为
t1: outside
t1: entered
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
t1: leaved
t1: outside
t1: entered
t2: leaved
t2: outside
t2: entered
为什么当t1线程在同步块里的时候,t2也可以进来啊?如果我把 num--; 这句注释掉就没有这个问题
谁能告诉我这是为什么啊???谢谢

------解决方案--------------------
明白了。

注意这里:
num--
这句相当于:
num = num - 1;
这里有自动拆箱和装箱的动作,首先,原来的num被拆成一个一般的int,用它跟1相减,然后其结果再被重新装箱成“另一个”Integer对象赋给静态变量num。

说起来好像挺复杂,但对你的问题而言,不需要知道那么多,只需要明白一点,经过“num--”之后,num变量就不再引用原来的那个对象了,这就使得两个线程完全可能开始在两个不同的对象上进行synchonized,于是它们也就互不干涉,互不影响,这也是为什么注释掉这句就没有问题的原因。

在这种情形下,如果要避免产生这种问题,可以考虑将num定义成static final的,那样的话,就不能进行“--”了(编译会帮你提示错误)。

如果确实需要“--”,就只能靠细心了。不过至少也应记住,自动装箱/拆箱要慎用,否则弄出问题,半天调试不出原因出在哪里。