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

为什么无论睡2500,6000。。。。多久,都是这样?怎么能让b=2000啊?


public class Why implements Runnable{
    int b=100;
public synchronized void m1() throws Exception{
    b=1000;
Thread.sleep(5000);
System.out.println("m1 of b="+b);

}
public synchronized void m2() throws Exception{
Thread.sleep(6000);
//Thread.sleep(2500);
b=2000;

}
public void run(){
    try{
    m1();
}catch(Exception e){
    e.printStackTrace();
}
}

public static void main(String [] args) throws Exception{
    Why tt=new Why();
Thread t=new Thread(tt);
t.start();
tt.m2();
System.out.println("main to print b="+tt.b);
}

}


--------
main to print=1000;
m1 of b=1000
????
可以帮我分析执行顺序吗

------解决方案--------------------
先执行m1,m1睡眠,回到main中执行m2,m2睡眠,又回到main,所以就先打印main to print
然后5s过去了,执行m1的print
把synchronized关键字去掉应该就可以了
------解决方案--------------------
个人浅见:

1 t.start(); 启动这个线程,等待虚拟机进行调度。
2 主线程执行m2()方法。因为这个方法加了同步(synchronized), 所以要看是否能得到这个锁。在上面第一步,t线程要等待虚拟机调度,所以一般情况下在m2运行时,m1()尚未运行,同步对象锁是空闲的
3 主线程m2()方法休眠6秒,因为是在同步方法里,所以不释放锁,(m1())因为得不到锁而继续等待。
4 主线程休眠结束,给b 赋值2000,m2()结束,同步锁释放。
5 主线程接着执行System.out.println("main to print b="+tt.b);语句。输出main to print b=2000 (但有可能没有执行完,步骤6开始了,那样会输出b=1000. 这块由随机性,并不是总输出1000)。
6 线程t马上得到同步锁,开始执行b=1000. 然后休眠。
7 m1 休眠结束,输出m1 of b=1000.

楼主想让b = 2000, 只能是 main to print b=2000,可以在m1()方法里,把b=1000;语句放在休眠之后。
------解决方案--------------------
下面贴代码请使用代码模板。

public class Why implements Runnable{
    int b=100;
public synchronized void m1() throws Exception{
    b=1000;
Thread.sleep(5000);
System.out.println("m1 of b="+b);

}
public synchronized void m2() throws Exception{
Thread.sleep(6000);
//Thread.sleep(2500);
b=2000;

}
public void run(){
    try{
    m1();
}catch(Exception e){
    e.printStackTrace();
}
}

public static void main(String [] args) throws Exception{
    Why tt=new Why();
Thread t=new Thread(tt);
t.start();
tt.m2();
System.out.println("main to print b="+tt.b);
}

}


--------
main to print=1000;
m1 of b=1000
????
可以帮我分析执行顺序吗

这样,别人看的清晰点,也愿意回答。

你这个代码是有可能得到2000的,如果你运行足够多次的话。关键在于,第一次拿到锁的是m1方法还是m2方法,如果第一次运行的是m1方法,那有可能输出2000了,你想要的结果。

你在里面sleep方法睡多久都没有用,因为你的方法上已经加了内置锁,在你一个方法中睡觉的同时,另外一个方法只能在这个锁上面等待,变成了串行执行。所以,m1m2两方法的顺序,决定了最后的结果。
------解决方案--------------------
我执行了你的代码,有时候会打印出2000的。这个主意还是多线程的问题。
1、首先这里有2个线程,1个是主线程,1个是t线程。
2、如果t线程的m1()方法被先执行,主线程的m2()方法后执行的话,就会打印出2000.
3、如果主线程的m2()方法先执行,t线程的m1()方法后执行的话,就可能打印出1000.
4、而且就算主线程的m2()方法执行完,即tt.m2()代码被执行完,cpu也可能立刻唤醒t线程去执行m1()方法,所以还是有可能先执行m1()方法,最后打印System.out.println("main to print b=" + tt.b);这句。
5、如果你一定要打印出2000的话,就在t.start()后面让主线程等待1秒,这样cpu就会立刻执行t线程,不会出现先执行主线程,后执行t线程的情况了。

Why tt = new Why();
Thread t = new Thread(tt);
t.start();
Thread.sleep(1000);
tt.m2();
System.out.println("main to print b=" + tt.b);

------解决方案--------------------
m1 sleep 5000
m2 sleep 6000 //把这里改成1000试试
------解决方案--------------------
楼上大家说的很好啊。就是主线程休息后怎么调度。mi 和M2 的执行顺序。一个是主线程和一个T1
线程。