A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 刘文超 中级黑马   /  2013-1-2 17:02  /  1924 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

为什么结果为:
2000
a =1000
b = 1000
竟然不是m1()先执行完、打印,而是主线程抢了先??
  1. package org.qyx.online;

  2. public class TestSynchro implements Runnable {
  3.         int b = 100;

  4.         public synchronized void m1() throws Exception {
  5.                 b = 1000;
  6.                 Thread.sleep(1000);
  7.                 System.out.println("b = " + b);
  8.         }

  9.         public synchronized void m2() throws Exception {
  10.                 Thread.sleep(2500);
  11.                 b = 2000;
  12.                 System.out.println(b);
  13.         }

  14.         public void run() {
  15.                 try {
  16.                         m1();
  17.                 } catch (Exception e) {
  18.                         e.printStackTrace();
  19.                 }
  20.         }

  21.         public static void main(String[] args) throws Exception {

  22.                 TestSynchro tt = new TestSynchro();
  23.                 Thread t = new Thread(tt);
  24.                 t.start();
  25.                 tt.m2();
  26.                 System.out.println("a =" + tt.b);
  27.         }
  28. }
复制代码

4 个回复

倒序浏览
Thread t = new Thread(tt);
                t.start();
这时候抢到线程,有可能没执行权,执行权在主函数里。
                tt.m2();
// 这里又调用 了方法 b=2000
//线程抢到执行权又运行了run方法 tt.b =1000

                System.out.println("a =" + tt.b);
//随后线程又休息  最后被唤醒后 又来一个 b=1000
结果故为:
2000
a =1000
b = 1000

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 神马都是浮云

查看全部评分

回复 使用道具 举报
本帖最后由 小律队员 于 2013-1-2 19:35 编辑

这里涉及到线程同步问题,说白了就是主线程和t两个线程同时执行,
两个都有锁,所以说白了就是看操作系统把cpu先给谁,运行过程如下:main开始,t.start()后,实际调用的是run方法,也就是m1()方法,线程同步,主线程继续,然后同时tt.m2()也被调用,看操作系统先给谁cpu(就是谁先得到cpu处理,cpu时间片)
如果m1先得到cpu,那么先执行完m1这个方法才能继续,(因为有锁)(可以理解为tt.m2()等着这把锁才能执行),结果是b被赋值1000,等1秒然后输出b = 1000,然后m2执行,等2.5秒,输出2000,再然后输出a = 2000。
如果m2先得到cpu,那么就是你这种结果了,先等2.5秒,然后输出2000,然后这时候m1拿到锁,和main(也就是m2以后的语句)一起执行,这时候b值被赋予1000,然后m1等1秒的过程中,main先打印a = 1000,然后m1再打印 b = 1000。

下面是我以前写的代码,之后总结出来的结论,和你的程序挺相似,只是为了扩大效果sleep时间有点长,其他还好。

无标题-2.jpg (142 KB, 下载次数: 46)

无标题-2.jpg

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 神马都是浮云

查看全部评分

回复 使用道具 举报
上面的的分析都很正确,是因为线程之间抢夺执行权导致的
我运行了下,还出现过这个结果:
2000
a =2000
b = 1000

要指定子线程和主线程哪个先运行的话,可以定义一个标记
回复 使用道具 举报
本帖最后由 何竹冬 于 2013-1-3 02:51 编辑

你好
这里有两个线程t线程和主线程在抢夺执行权。

如果t线程抢到执行权执行m1方法遇到sleep后t线程进入休眠状态放弃执行资格,休眠结束后进入线程池进入阻塞状态,也就是说有了执行资格没有执行权,等待被唤醒。
这时主线程获得执行权,执行m2方法时遇到sleep后主线程进入休眠状态放弃执行资格,休眠结束后进入线程池进入阻塞状态,这时主线程有执行资格没有执行权,等待被唤醒。
这时两个休眠线程都要被唤醒,线程池中等待的线程通常先进入的先被唤醒所以t线程先被唤醒打印b=1000后t线程结束放弃执行权,主线程获得执行权执行m2打印2000最后打印a=2000.

如果主线程抢到执行权同理可以得到打印结果2000,a=100,b=1000.

不过他们抢到执行权的机会是随机的,所以可能试很多次都只有一种结果,我试了n次才找到先打印b=1000的结果。你可以设置主函数和t线程的优先级然后在看一下打印结果。为了明显看到打印结果开启多个线程和主线程抢夺执行权。
  1. 01.package org.qyx.online;

  2. public class TestSynchro implements Runnable {
  3.         int b = 100;
  4.         public synchronized void m1() throws Exception {
  5.                                 //System.out.println("m1 run");
  6.                 b = 1000;
  7.                 Thread.sleep(100);
  8.                 System.out.println("b = " + b);
  9.         }
  10.         public synchronized void m2() throws Exception {
  11.                                 //System.out.println("m2 run");
  12.                 Thread.sleep(250);
  13.                 b = 2000;
  14.                 System.out.println(b);
  15.         }
  16.         public void run() {
  17.                 try {
  18.                         m1();
  19.                 } catch (Exception e) {
  20.                         e.printStackTrace();
  21.                 }
  22.         }
  23.         public static void main(String[] args) throws Exception {
  24.                 TestSynchro tt = new TestSynchro();
  25.                                 //设置主函数优先级最高
  26.                                 Thread.currentThread().setPriority(10);
  27.                                 for(int i=0;i<10;i++)
  28.                                 {
  29.                                         Thread t = new Thread(tt);
  30.                                         //设置t线程优先级最低
  31.                                         t.setPriority(1);
  32.                                         t.start();
  33.                                 }
  34.                 tt.m2();
  35.                     System.out.println("a =" + tt.b);
  36.         }
  37. }
复制代码

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 神马都是浮云

查看全部评分

回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马