请教:scjp中一道常见的多线程问题,不大明白 :)

z_j_zhou 2004-09-07 08:47:20
6 of 62、 What is the result?

public class MultiThread implements Runnable
{
private int x;
private int y;

public static void main(String args[])
{
MultiThread one = new MultiThread();
(new Thread(one)).start();
(new Thread(one)).start();
}

public void run()
{
for(;;)
{
x++;
//难道在这时候不会转换线程?
y++;
System.out.println("x=" + x +" , y=" + y);
}
}
}

A. Errors at lines 7 and 8 cause compilation to fail.
B. The program prints pairs of values for x and y that might not always be the same
on the same line (for example, “x=2, y=1”).
C. The program prints pairs of values for x and y that are always the same on the
same line (for example, “x=1, y=1”. In addition, each value appears twice (for
example, “x=1, y=1” followed by “x=1, y=1”).
D. The program prints pairs of values for x and y that are always the same on the
same line (for example, “x=1, y=1”. In addition, each value appears only for
once (for example, “x=1, y=1” followed by “x=2, y=2”).
正确答案: D

若在我注释的地方,线程转换了,那么x就会被执行两次 x++; 这样的话打出来的就不会每次都相等,所以,这道题,我认为应该选B。 可是很多模拟题给的正确答案都是 D 。郁闷!
能把我说服就给分结贴,谢谢!
...全文
723 56 打赏 收藏 转发到动态 举报
写回复
用AI写文章
56 条回复
切换为时间正序
请发表友善的回复…
发表回复
squeal 2004-12-01
  • 打赏
  • 举报
回复
我运行之后觉得应该是D选项吧
z_j_zhou 2004-12-01
  • 打赏
  • 举报
回复
如果这个问题引起了您对这个问题的思考,并有了您自己的思路,那么这个讨论的目的就达到了。综合以上各位朋友的发言,我还是认为答案应该是B,因为这样才能够合理解释清楚。不过,如果您正在准备考试的话,建议死记住这道题,答成D,能帮助你提高2个%,本人9月底96%通过scjp1.4,错了两道题,其一就是这个,因为我执著地认为应该是B。

感谢在此问题讨论中朋友们给于的真诚帮助,至于其中出现的不和谐音符,我们大可不必去理会它。

就此结贴。
sysmaster 2004-12-01
  • 打赏
  • 举报
回复
答案是D,考点是线程间的数据共享。
z_j_zhou 2004-11-22
  • 打赏
  • 举报
回复
没想到我提的这个问题引起这么强烈的讨论。虽然是一个比较菜的问题,但相信对一些初学的朋友还是有帮助的(至少对我是有帮助),大家要采取互相学习的态度来发言,不要互相攻击,尺有所短,寸有所长,其实从大家的讨论中相信可以帮朋友们明确一些对概念的理解。恳请高手不要对我们这样的菜鸟问题表示鄙夷。我们正是因为对这样的问题不能理解才来请教的,请不要打击我们本就脆弱的信心。恃才傲物不应该是程序员的代名词,文人相鄙更不应该是我们现代中国人的品质。为了csdn这个讨论技术的社区的纯净的天空,请大家不要互相谩骂,也不必嗔怒于个别人的无礼,发言贴在这里,公道自在人心,相信大家的眼睛,孰是孰非,瑕瑜自见,提倡“superman421(38度的雪) ”和“metaphy(突然发现自己生活在一个垃圾场) ”朋友这样的对问题的讨论。

一家之言,有得罪的朋友多多担待!

这个问题我认为讨论的还是比较深入的,大家如果没有什么新的见解,过几天就结贴了。
superman421 2004-11-20
  • 打赏
  • 举报
回复
楼上有一位把输出改为
if (x !=y)
System.out.println(tn + ": x=" + x + " , y=" + y);
的结果不能做这个问题的实验,因为得到tn用了含synchronized的方法!Thread.getName()

我做了一下是
x=97486645 , y=121962384
x=97486646 , y=121962385
x=97486647 , y=121962386
x=97486648 , y=121962387
x=97486649 , y=121962388
x=97486650 , y=121962389
x=97486651 , y=121962390
x=97486652 , y=121962391
x=97486653 , y=121962392
x=97486654 , y=121962393
x=97486655 , y=121962394
x=97486656 , y=121962395
x=97486657 , y=121962396
x=97486658 , y=121962397
x=97486659 , y=121962398
x=97486660 , y=121962399
x=97486661 , y=121962400
x=97486662 , y=121962401
superman421 2004-11-20
  • 打赏
  • 举报
回复
还有一点忘了说了,如果发生数据不一致,肯定是y>x
这点大家的结果都证明了。
superman421 2004-11-20
  • 打赏
  • 举报
回复
答案可能不正确!
在多线程环境中安全问题是最为重要的,不能安全控制并发控制的应用程序在大部分时候能够正常工作(也许几乎所有时间均能正常工作),

但有时会发生错误的结果。
我做了一下证明,不对请指出!

证明过程我分为两步:
1,证明对一个结果可能显示两次。
2,证明每次显示x和y的值可能不一致。

证明如下:

当一个方法同时在两个或更多线程中被访问时,每个线程都会有自己的局部拷贝。只有用volatile修饰的变量,VM才不会不会为它分配局部拷贝,才会直接使用共享拷贝。但是在synchronized的同步块之后,系统会自动保持共享拷贝和私有拷贝的一致。更重要的一点是synchronized分布在系统的很多类之中,例如java.*中。System.out.println()就包含一个synchronized。系统认为该保持一致时,也会调整!

下面一段程序演示系统是如何更新的(注意我们运行的环境是单处理器):
public class MultiThread
{
private int x;
private int y;

public void oper(int sleeptime){
x++;
try{Thread.sleep(sleeptime);}catch(Exception e){}
y++;
}

public int getX(){
return x;
}

public int getY(){
return y;
}

public static void main(String args[])
{
final MultiThread one = new MultiThread();
Runnable r1=new Runnable(){
public void run(){
for(int i=0;i<3;i++)
{
one.oper(1000);
System.out.println("x="+one.getX()+"y="+one.getY()+" "+
Thread.currentThread().getName());
}
}
};
Thread t1=new Thread(r1);
t1.start();
Runnable r2=new Runnable(){
public void run(){
for(int i=0;i<3;i++)
{
one.oper(2000);
System.out.println("x="+one.getX()+"y="+one.getY()+" "+
Thread.currentThread().getName());
}
}
};
Thread t2=new Thread(r2);
t2.start();
}
}

//运行结果如下:
x=2y=1 Thread-0
x=3y=2 Thread-0
x=4y=3 Thread-1
x=5y=4 Thread-0
x=5y=5 Thread-1
x=6y=6 Thread-1
Press any key to continue...

从结果可以很清楚的看出系统是怎样更新私有拷贝与共享拷贝的(与楼主问题略有不同,sleep是同步的)。
Thread-0首先运行,在执行x++后休眠,此时变量为 x=1,y=0;
Thread-1运行,在执行x++后休眠,此时变量为 x=2,y=0;
Thread-0运行,执行y++,打印结果, x=2,y=1
Thread-0运行,执行x++后休眠,变量为 x=3,y=1
Thread-1运行,执行y++,打印结果, x=3,y=2
.......


我们会发现,system.out.println是在执行了x++和y++之后执行的。换句话说,x,y的值是在执行system.out.println之前是线程的私有拷贝,它的变化不会影响其它线程。只有在执行了system.out.println之后才会使共享拷贝和私有拷贝保持一致。

我们可以假设某时刻x与y的值保持一致(设x=X1,y=Y1),这点很显然,至少启动时是。

证(1)

thread-i在x++之前中断或之后中断,Thread-i的局部拷贝是x=X1,y=Y1或x=X1+1,y=Y1+1,thread-j开始执行,初始值x=X1,y=Y1,执行若干次后为X1+n,Y1+n,再执行system.out.println显示结果,使thread-i中的局部变量调整为x=X1+n,y=Y1+n,thread-i执行system.out.println显示结果x=X1+n,y=Y1+n,既一个结果出现两次!


证(2)

Thread-i在x++后中断,Thread-i的局部拷贝是x=X1+1,y=Y1,thread-j开始执行,初始值x=X1,y=Y1,执行若干次后为X1+n,Y1+n,再执行system.out.println显示结果,使thread-i中的局部变量调整为x=X1+n,y=Y1+n,thread-i执行y++,使x=X1+n,y=Y1+n+1,再执行system.out.println,thread-j中局部变量调整为x=X1+n,y=Y1+n+1。 不一致!

问题证毕!

所结果就和系统调度有关!这么多人都有不同的结果,相信也是有道理的!实际编程这种问题肯定是要排除的!不晓得出这种题干什么!

一小段结果:
x=11408980 , y=11408983
x=11408981 , y=11408984
x=11408982 , y=11408985
x=11408983 , y=11408986
x=11408984 , y=11408987
x=11408985 , y=11408988
x=11408986 , y=11408989
x=11408987 , y=11408990
x=11408988 , y=11408991
x=11408989 , y=11408992
x=11408990 , y=11408993
x=11408991 , y=11408994
x=11408992 , y=11408995
x=11408993 , y=11408996
x=11408994 , y=11408997
x=11408995 , y=11408998
x=11408996 , y=11408999
x=11408997 , y=11409000
x=11408998 , y=11409001
x=11408999 , y=11409002
x=11409000 , y=11409003
x=11409001 , y=11409004
x=11409002 , y=11409005
x=11409003 , y=11409006
pbMaster 2004-11-19
  • 打赏
  • 举报
回复
在完全取决于操作系统和VM。
baffling 2004-11-19
  • 打赏
  • 举报
回复
gz
fjsl 2004-11-18
  • 打赏
  • 举报
回复
拷,这么老的问题还在讨论,晕......
metaphy 2004-11-18
  • 打赏
  • 举报
回复
大家最好不要吵架和骂人
metaphy 2004-11-18
  • 打赏
  • 举报
回复
真诚的希望大家动手试验下:

(new Thread(one)).start();
(new Thread(one)).start();
这段代码生成了两个引用( reference );但指向同一内存区间,也就是说它们拥有同一个x和同一个y, 因此不会出现 x=1,y=1;x=1,y=1;x=2,y=2;x=2,y=2;这样的现象;而这段代码:
x++;
//难道在这时候不会转换线程?
y++;
System.out.println("x=" + x +" , y=" + y);
在注释处完全可以出现“线程转换”,所以x 和 y不相等的时候肯定会出现


稍微修改了一下:
/**
* @author metaphy
*/
public class MutiThread implements Runnable
{
private long x ;
private long y ;
private int num = 0 ;
public static void main(String args[])
{
MutiThread one = new MutiThread();
(new Thread(one)).start();
(new Thread(one)).start();
}

public void run()
{
for(;;)
{
x++;
y++;
if (x!= y && num <20){
num ++ ;
System.out.println("x=" + x +" , y=" + y);
}
}
}
}



zhengcg 2004-10-31
  • 打赏
  • 举报
回复
昨天刚考 SCJP ,75% 通过了,认为太低了。其中 Thread 的正确率最低,还是有点难度的。
其中也有一道类似的题(凭记忆是一样的),除了在 for(;;) 语句前有一个 synchronized 修饰。所以我选择了 D,不知道对错。
bigc2000 2004-10-30
  • 打赏
  • 举报
回复
awers(狰狞中!!) 说的对.
这是我的一点愚见:
我第一次看,我觉得选择D是有道理的。
因为java 多线程设计时,优先级相同时, 不会主动让出cpu的.
但是,这与OS 相关,有的用分时轮转,有的用优先级调度,多级轮转,有的多者兼备.
还有实时操作系统.
所以,线程在 java 虚拟机种虽然没有可能去主动让cpu.
但是,OS如win ,肯定会让多个线程得到执行,即便是优先级高的,也不能始终占有时间片.

所以我倾项B.在实际windows下也确实是B

编程夜猫 2004-10-30
  • 打赏
  • 举报
回复
给大家看个有趣的现象

x=22472 , y=22472
x=22473 , y=22473
x=22474 , y=22474
x=22475 , y=22475
x=22476 , y=22476
x=22477 , y=22477
x=22478 , y=22478
x=22479 , y=22479
x=22480 , y=22480
x=22481 , y=22481
x=22467 , y=22482
x=22468 , y=22483
x=22469 , y=22484
x=22470 , y=22485
x=22471 , y=22486
x=22472 , y=22487

x突然就小了,哈哈
sunlm78 2004-10-28
  • 打赏
  • 举报
回复
mark
bighappy 2004-10-28
  • 打赏
  • 举报
回复
以后加上操作系统以Solaris为准,一切在windows平台上出现的问题由bill负责,与sun无关~~~~~
tommorrow 2004-10-20
  • 打赏
  • 举报
回复
正确答案在此,都不要争了。
答案肯定是d。你们都是试验过了。shihuash11(ssh) 说得没错,
这段程序中run函数的无限循环没有主动放弃线程的语句,比如sleep,所以当前线程肯定不会放弃执行的。不过windows操作系统的调度方式会保证每个线程都有机会执行的。所以你们的结果也不奇怪。你去Solaris下用绿色线程试试看。保证不会出现线程切换的情况!
awers 2004-10-20
  • 打赏
  • 举报
回复
别争了,J@Whiz1.4的答案很准对吧?去做做看,我记的里面类似的问题有至少3道,答案都是“根据不同的操作系统,返回值会不一样”,印象很深哦!只怪这题给的答案不严谨,哎~~~
Xtyun 2004-10-20
  • 打赏
  • 举报
回复
学习中
加载更多回复(36)

62,616

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧