各位好~~
本人在学习线程的时候碰到一个问题
以下是代码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--; 这句注释掉就没有这个问题
谁能告诉我这是为什么啊???谢谢

解决方案 »

  1.   

    Test t1 = new Test("t1");
    Test t2 = new Test("t2");
    Thread th1 = new Thread(t1);
    Thread th2 = new Thread(t2); 你同步了什么东西?2个线程自己玩自己的,输出是随机。
      

  2.   

    明白了。注意这里:
    num--
    这句相当于:
    num = num - 1;
    这里有自动拆箱和装箱的动作,首先,原来的num被拆成一个一般的int,用它跟1相减,然后其结果再被重新装箱成“另一个”Integer对象赋给静态变量num。说起来好像挺复杂,但对你的问题而言,不需要知道那么多,只需要明白一点,经过“num--”之后,num变量就不再引用原来的那个对象了,这就使得两个线程完全可能开始在两个不同的对象上进行synchonized,于是它们也就互不干涉,互不影响,这也是为什么注释掉这句就没有问题的原因。在这种情形下,如果要避免产生这种问题,可以考虑将num定义成static final的,那样的话,就不能进行“--”了(编译会帮你提示错误)。如果确实需要“--”,就只能靠细心了。不过至少也应记住,自动装箱/拆箱要慎用,否则弄出问题,半天调试不出原因出在哪里。
      

  3.   

    仔细想本质上也不是拆箱装箱造成的问题。Java1.4及以前倒是不支持自动装箱拆箱。但像对String这种+=操作,也会引起类似微妙的问题。
    比如:
    String s = ...;
    s += ...
    后面这句看起来挺无辜的,实质上也是相当于:
    s = s + ...;
    如果用在楼主的例子中,也同样会出现令人奇怪的结果。
    所以,只要是非内建类型在而且支持除"="以外的赋值,不管是由于装箱拆箱,还是由于本来就支持,用得时候都得细心一点。如果出了令人奇怪的问题,也尽量先想想这些方面。
      

  4.   

    顶4楼应该是locker的引用发生变化了