版主你秀逗了吧。。从1加到50,不是50+50.。最大值是2550
同学,你再看看题?不是sum=sum+i哦~
解决方案 »
- ObjectInputStream readObject 连续读对象的问题
- Java中GridLayout如何3行2列?
- ProcessBuilder问题~
- java返回值,不用return如何得到返回值
- 怎么关掉线程池
- 请问:如何实现文件日志功能?要求每天换一个文件。文件名以日期区分
- 怎样判断一个己知点在一个矩形内?
- 为何用appletviewer 能执行applet,但在html文件里却没显示出来?
- 看过jb6实例入门的人进来看看 会jb的也可以 来者有分
- JB8的2问:怎么把光标和输入位置对齐?
- 请教个SocketException Socket is closed异常问题
- 还有一道题入门题求助!
public int sum = 0;
/**
* @param args
*/
public static void main(String[] args) {
Threads ts = new Threads();
Thread t1 = new Thread(ts);
Thread t2 = new Thread(ts);
t1.start();
t2.start();
try {
Thread.sleep(5000);//保证两个线程都执行完
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(ts.sum);
} public void run() {
for (int i = 1; i <= 50; i++) {
sum=sum+i;
}
}}
sum=2550
首先不可能超过100.
其次不管是哪个线程,当允许最后一次的求和时取到的sum值一定是被加上的,即便是被另外一个线程修改过,也一定是加上过的,所以一定取得的sum值最小是1,那么加上之后结果一定不小于2.
那么一定是2-100之间的值。现在考虑所有的都可能被取到。
对于50-100之间比较好理解。让其中一个线程取加sum到0-50之间的值,然后另外一个线程取到这个值,第一个线程运行完成之后,再由第二个线程取到在刚才得到的值上加50次就可以得到50-100之间的值.这个需要4次配合
2-49之间的值几乎不可能,但是仍然有可能发生这种奇迹.
首先让第一个线程取得sum=0,然后让第二个线程循环49次.接着用第一个线程运行到1-50之间的值,然后第二个线程取得这个值,接着第一个线程运行完,第二个线程在这个值的基础之上加1,于是就可以得到2-51之间的值.这个需要6次配合。
我以极端的2为例子,说明这一点
请看代码:
package com;
public class Threads extends Thread {
public static int sum = 0;
public static int state=2;
public static Object obj=new Object();
public boolean sub;//true为第一个线程,false为第二个线程
/** * @param args */
public static void main(String[] args) {
Thread t1 = new Threads(true);
Thread t2 = new Threads(false);
t1.start();
t2.start();
while(state!=0){
}
System.out.println(sum);
}
public Threads(boolean value){
sub=value;
}
public void run() {
if(sub){
for (int i = 1; i <= 50; i++) {
int value=sum;//取sum值
if(i==1){
try {
Thread.sleep(100);//第一个线程取得0时等一会
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
sum=value+1;//sum值加1
if(i==1){
try {
Thread.sleep(200);//第一个线程赋值为1时等待第二线程取到1时再运行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}else{
try {
Thread.sleep(1);//第二个线程延迟一会执行
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 1; i <= 50; i++) {
int value=sum;//取sum值
if(i==50){
try {
Thread.sleep(250);//从第一个线程取得1之后等第一个线程运行完再执行加到2
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
sum=value+1; //sum值加1
if(i==49){
try {
Thread.sleep(150);//第一个循环完49次之后等一会
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
synchronized(obj){
state--;
}
}
}
取值范围应该在 50~100 之间,主要是线程之间相互覆盖计算结果问题,最差也就相当于只跑了一次单线程的效果。不过因为循环太短了,估计还没等第二个线程启动第一个线程就已经运行结束,所以靠近100的概率很高。+1,run方法循环时间太短了,可能第二个还没开始,第一个就走完了,约100。。
看了一遍,觉得还是挺有道理的。仔细看了你的代码,其中有些存在异议的地方,探讨一下:
其中int value=sum;这种写法相当于定义了一个临时变量保存了sum等于0时的状态,当线程2循环49次后可以从value这个临时变量中取得0;
而题目中代码sum=sum+1;的这种写法,当线程2循环49次后其中标红的sum还有没有可能是0呢?
取值范围应该在 50~100 之间,主要是线程之间相互覆盖计算结果问题,最差也就相当于只跑了一次单线程的效果。不过因为循环太短了,估计还没等第二个线程启动第一个线程就已经运行结束,所以靠近100的概率很高。+1,run方法循环时间太短了,可能第二个还没开始,第一个就走完了,约100。。我觉得也是这样的
这是Java:
package com.test;public class Test {
public static void main(String[] args) {
int sum = 0;
for(int i=0;i<10;i++) {
sum = sum+1;
}
System.out.println(sum);
}
}
这是对应的反汇编:
D:\Code\WorkSpace_3.6\Test\bin\com\test>javap -c Test
Compiled from "Test.java"
public class com.test.Test extends java.lang.Object{
public com.test.Test();
Code:
0: aload_0
1: invokespecial #8; //Method java/lang/Object."<init>":()V
4: returnpublic static void main(java.lang.String[]);
Code:
0: iconst_0
1: istore_1
2: iconst_0
3: istore_2
4: goto 13
7: iinc 1, 1
10: iinc 2, 1
13: iload_2
14: bipush 10
16: if_icmplt 7
19: getstatic #16; //Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #22; //Method java/io/PrintStream.println:(I)V
26: return}
可以从第7行看到, 对sum的+1操作,只用了一行,而在17楼的示意代码中,是先把sum的值取出来,然后运行线程2,再回过来用这个sum的值,所以对于这处,我还有一点疑问: 示意代码会不会破坏了原题的代码语义呢?
看了一遍,觉得还是挺有道理的。仔细看了你的代码,其中有些存在异议的地方,探讨一下:
其中int value=sum;这种写法相当于定义了一个临时变量保存了sum等于0时的状态,当线程2循环49次后可以从value这个临时变量中取得0;
而题目中代码sum=sum+1;的这种写法,当线程2循环49次后其中标红的sum还有没有可能是0呢?
线程取sum值其实是临时地将值放在内存中,但是没有改变sum的值,这个和局部变量存储差不多,只是把过程分解容易控制而已,局部变量是线程内部的,完全模拟封装了虚拟机的栈.
你也可以写成int value=sum+1,sum=value;
sum=sum+1;关键是取sum和赋值sum两个过程
你也可以写成int value=sum+1,sum=value;
sum=sum+1;关键是取sum和赋值sum两个过程恩, 的确, 反编译带thread的code时, 取值与赋值是分开的操作.
看来应该是局部变量与Thread里操作全局变量的不同导致的
7: getfield #14 // Field sum:I
10: iconst_1
11: iadd
12: putfield #14 // Field sum:I
/** * @param args */
public static void main(String[] args) {
Test2 a=new Test2();
Thread t1=new Thread(a);
Test2 b=new Test2();
Thread t2=new Thread(b);
t1.start();
t2.start();
}
}class Test2 implements Runnable{
public static int sum = 0;
public void run() {
// TODO Auto-generated method stub
for(int i=1;i<=50;i++){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sum=sum+1;
}
System.out.println(sum);
}
}
经过代码测试结果应该是100-200
调用start并不一定线程就执行了.