package com.bjsxt.thred ;
public class TT implements Runnable {
int b = 100;
public synchronized void m1() throws Exception{
b = 1000;
Thread.sleep(1000);
System.out.println("b = " + b);
}
public synchronized void m2() throws Exception {
Thread.sleep(2500);
b = 2000;
System.out.println(b);
}
public void run() {
try {
m1();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
TT tt = new TT();
Thread t = new Thread(tt);
t.start();
tt.m2();
System.out.println("a =" + tt.b);
}
}
//为什么这段代码的最后输出是:
//2000
//a =2000
//b = 1000
//关于线程同步的执行先后问题,有点头大啊,哪位大神,帮忙解释一下呢?我怎么感觉b = 1000 应该先打印啊。。
我把程序改动改动,发现一个问题 ,不管谁先输出,a = 2000总是跟第一句话同时打印,总是在第二句打印,这是为什么呢?小弟不才~~!!

解决方案 »

  1.   

    m1() 和 m2() 谁先抢到锁谁就先执行,由于m2在主线程中执行,所以它执行完了,后边的System.out.println("a =" + tt.b);才能执行到,这就是它总是跟在m2打印结果后边的原因
      

  2.   

    t.start()创建了一个新的线程,但是主线程依旧在往下执行,主线程进入synchronized方法比t早,(这个无法解释,可能是语句过多??高手指点)tt.m2()是一个被synchronized修饰的方法,这个方法只要有一个线程访问,那么被synchronized的其它方法就不能同时执行,所以在tt.m2()执行完了以后t.start()中调用的m1方法开始执行,其中有个sleep()所以主线程的System.out.println("a =" + tt.b);先输出
      

  3.   

    在main方法中现在有两个线程,一个是新建的t另外一个就是主线程,在t.start()时,主线程仍在向下执行,主线程先执行到被synchronized修饰的方法,如果有多个方法被synchronized修饰时,如果有一个方法在执行,那么其它线程不能同时访问这个对象中任何一个synchronized方法,所以t.start()在执行m1()之前,主线程已经执行m2(),t只能等待,在m2()执行完后m1()开始执行,由于m1中有sleep方法,所以m1的输出语句比主线程的输出语句System.out.println("a =" + tt.b);晚。
      

  4.   

    在m1中,调用了sleep方法,此时m2抢到执行权,进入m2,b=2000执行,执行System.out.println(b);输出2000.然后执行主线程中的System.out.println("a =" + tt.b);因此输出a=2000
      

  5.   

    我的一点见解,请各位大虾指教
    程序执行的顺序可以从这三句开
    t.start();
    tt.m2();
    System.out.println("a =" + tt.b);下面逐句分析:
    t.start();
    表示线程启动,但是启动不是代表马上就执行run()里的语句(操作系统决定)
    所以:
    tt.m2();
    得到执行,由于m2是同步方法,所以进入后锁定当前对象this,拿到锁了
    m2进入睡眠,这时m1可能已经得到时间片了,开始执行了,由于m1也是
    同步方法,所以它必须先拿到锁,但是锁已经被m2先拿到了,所以它必须等待
    m2执行完才能够继续执行,故:
    首先输出:2000
    m2执行完毕,现在有2条路,第一条是m1要执行,第二条是main要继续执行
    到底谁先执行,还是操作系统说了算,
    如果main先,那么输出:a = 2000 ,然后m1执行输出 b=1000
    如果m1先,那么b=1000,m1睡眠,继续main执行,故输出:
    a=1000   b=1000
      

  6.   

    public class ThreadTest implements Runnable {
    int b = 100; public synchronized void m1() throws Exception {
    System.out.println("m1.....");
    b = 1000;
    Thread.sleep(1000);
    System.out.println("b = " + b);
    } public synchronized void m2() throws Exception {
    System.out.println("m2.....");
    Thread.sleep(2500);
    b = 2000;
    System.out.println(b);
    } public void run() {
    System.out.println("run.....");
    try {
    m1();
    } catch (Exception e) {
    e.printStackTrace();
    }
    } public static void main(String[] args) throws Exception {
    ThreadTest tt = new ThreadTest();
    Thread t = new Thread(tt);
    t.start();
    //tt.run();
    tt.m2();
    System.out.println("a =" + tt.b);
    }
    }
    好一番研究啊,lz我将你代码加了几句打印语句,大胆猜测其中原理:
    首先贴出运行结果m2.....
    run.....
    2000
    m1.....
    a =1000
    b = 1000
    其实从打印结果基本就知道了,问题重点是先运行run()还是m2(),先拿到锁就先执行,因为是锁住整个对象。首先main线程执行栈中必然是t.start()先运行(靠前),但是这里运行的是Thread类的一个实例t的方法,看看Thread类部分源码public synchronized void start() {
            if (threadStatus != 0)
                throw new IllegalThreadStateException();
            group.add(this);
            start0();
            if (stopBeforeStart) {
        stop0(throwableFromStop);
    }
        }
        private native void start0();
        public void run() {
    if (target != null) {
        target.run();
    }
        }
    start()方法里边执行了这么多步,最后还要由JVM去执行run(),跑一个单独线程有这些东西。反观tt.m2()直接调用自己类中方法,虚拟机中就是一两个引用,自然就是先执行m2()了。
    PS:打开tt.run();//注释tt.m2();执行结果(先执行run()):
    run.....
    m1.....
    run.....
    b = 1000
    a =1000
    m1.....
    b = 1000