为了模拟线程计数(锁的可重入性),写了一个简单的代码,却遇到奇怪问题。100分求助
count += m2();//不是我想当然的认为的那样,为什么?
public class Odd{
private int count =0;
public void m1( ){
count++;System.out.println("1:"+get());
int i = m2();//调用m2()
count = count + i;
//count += m2();//奇怪
System.out.println("2:"+get());
count += m2();
System.out.println("3:"+get());
}
public int m2(){
count++;
return -1;
}
public int get(){
return count;
}
}
count += m2();//不是我想当然的认为的那样,为什么?
public class Odd{
private int count =0;
public void m1( ){
count++;System.out.println("1:"+get());
int i = m2();//调用m2()
count = count + i;
//count += m2();//奇怪
System.out.println("2:"+get());
count += m2();
System.out.println("3:"+get());
}
public int m2(){
count++;
return -1;
}
public int get(){
return count;
}
}
count += m2();
后count的值应该不变,是这样吗实际上
比如,x += 10;
就相当于 x= x+10;
x的值当然会变这和x++不同
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int x = 10;
System.out.println("x is:"+(x++));
System.out.println("x is:"+x);
}
}打印结果是x is:10
x is:11第二个例子public class Test1 { /**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int x = 10;
System.out.println("x is:"+(x+=20));
}
}打印结果x is:30输出的是
int i = m2();//调用m2()
count = count + i;
}Vs
count += m2();//奇怪
count = count + m2();执行时,
1、以临时变量保存提取的count,并转入 m2()
2、m2将count加1,但是不影响临时变量中的值
3、临时变量-1并刷新count。研究字节码的朋友,证实一下。
另外开帖加80分
* ReentrancyDemo.java:
* 本类
* @作者(yqj2065)
* @版本(一个版本号或者一个日期)
*/
public class ReentrancyDemo{
private int count =0;//模拟,因为退出synchronized方法
public void m1( ){
synchronized(this){
count++;//进入synchronized块,获得锁
System.out.println("进入被同步块:"+get());
{
int i = m2();//调用m2()
count = count + i;
//count += m2();//奇怪
System.out.println("退出被同步方法:"+get());
}
//again
{
int i = m2();//调用m2()
count = count + i;
//count += m2();//奇怪
System.out.println("退出被同步方法:"+get());
}
}
count--;
System.out.println("退出被同步块:"+get());
}
public synchronized int m2(){
count++;//进入synchronized块,获得锁
System.out.println("进入被同步方法:"+get());
return -1;//退出方法,
}
public int get(){
return count;
}
}
确实欠妥!
执行过程如下:
81: aload_0
82: dup
83: getfield #2; //Field count:I 将count的值读取到栈顶,此时栈顶值是1
86: aload_0
87: invokevirtual #12; //Method m2:()I 调用m2(),得到结果-1保存在栈顶
90: iadd 相加(1+(-1)=0)
91: putfield #2; //Field count:I 将结果存回到count再看m2()
public int m2();
Code:
0: aload_0
1: dup
2: getfield #2; //Field count:I
5: iconst_1
6: iadd
7: putfield #2; //Field count:I 将加1后的结果保存到count
10: iconst_m1
11: ireturn
count += m2();
其实就是先将左操作数的值复制出来,再准备右操作数(此过程中会修改左操作数的原值,但是不影响我们已经加载到栈里的值),执行加法,写回count。中间对count写回了两遍,不过m2()中的写回被后面一次写回覆盖掉了如果看过i=i++;类似的问题,这个应该容易理解。
i=i++;的问题可以参考:
http://blog.csdn.net/ZangXT/archive/2008/11/05/3229281.aspx
count = count + m2();System.out.println(count); // -1和
i=i++; vs i=++i;
一样。
很无聊的Java。