我这个程序只是为了解决我的一个疑问随便写的,运行过没问题,里面2个方法,我就是想看哪个先执行
在主方法里面开了个线程,也就是调用m1,主方法里马上调用m2,结果是什么我知道,为什么,望高手解答
public class SynchronizedTest extends Thread {
int a = 100; synchronized void m1() {
System.out.println("m1 start");
a = 500;
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m1 is over, a is : " + a);
} synchronized void m2() {
System.out.println("m2 start");
a = 1000;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("m2 is over , a is : " + a);
} public void run() {
m1();
} public static void main(String[] args) {
SynchronizedTest st = new SynchronizedTest();
System.out.println("game start");
st.start();//开启线程
st.m2();//这算是同时调用2个锁方法吗,如果算是同时,为什么会是下面这个先得到锁呢???
}}

解决方案 »

  1.   

    调用st.start方法是开始启动这个线程,但不一定马上就执行,也就是说不一定马上就run;而st.m2()是调用成员方法,只要这个对象存在就会马上执行这个方法。
      

  2.   

    public class Test extends Thread {
    int a = 100; synchronized void m1() {
    System.out.println("m1 start");
    a = 500;
    try {
    Thread.sleep(5000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("m1 is over, a is : " + a);
    } synchronized void m2() {
    System.out.println("m2 start");
    a = 1000;
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
    System.out.println("m2 is over , a is : " + a);
    } public void run() {
    m1();
    } public static void main(String[] args) {
    Test t = new Test();
    t.start();
                    //main线程休眠
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    t.m2();
    }
    }
    1楼的回答似乎应证了我的测试,我的理解是main方法是一个线程,然后主线程休眠就能体现出这个"并不马上执行的"说法出来了.
      

  3.   

    回答4楼,我也做了同样的测试,sleep 1毫秒就够了,运行10多次,都是m2先执行
      

  4.   

    这就有关线程的内部机制了,Thread start()后,并不是立即执行run(),而是要等待获取系统执行锁,而你例子中SynchronizedTest的m2方法在主程序运行时调用,并不需要主线程去获取系统锁,所以基本不耗时间,而m1方法要在SynchronizedTest线程启动后才执行,这个过程由于线程锁(并不是你在SynchronizedTest定义的锁,是系统级的)的关系,相对更耗时。
      

  5.   

    答:这个问题没有多大意义。我们不应该假设:st.m2()就一定先执行。我们应该认为:这两个“方法”是打上引号的“同时”执行的。即:我们就按“同时”执行来理解。一定不要“依赖于st.m2()”先执行--这个假设来设计程序,这很不好。
    一句话:你应该理解成:它们“同时”执行了,谁先谁后,都有可能,但没有意义。因为写程序不能依赖于这一点来写。
      

  6.   

    答:呵呵。。,其实8楼的解释是错误的。如“而你例子中SynchronizedTest的m2方法在主程序运行时调用,并不需要主线程去获取系统锁,所以基本不耗时间”main方法中执行m2()时,怎么可能不需要获取对象锁呢?当然需要获取对象锁了
      

  7.   


    对象锁当然要获取了,我说的耗时是在取对象锁之前取系统锁的耗时!对象锁m1和m2都是公平的,看谁竞争得过谁,而系统锁在这里是不公平的,例子中的m2在执行的时候,是在同一个main线程中,不存在竞争,但m1的执行就不同了,它是在main线程外其它的线程中执行。
      

  8.   

    一定不要“依赖于st.m2()”先执行--这个假设来设计程序,这很不好。
     
    说得在理。
      

  9.   

    答:呵呵8楼说的是错误的,怎么还有人认识不到这个错误呢?我感到很费解。
    我来仔细分析8楼的错误在何处:
    1)核心的地方是系统锁的获取[不是对象锁]。那我们就来谈谈系统锁。8楼所谓的系统锁,是指:Thread start()后,并不是立即执行run(),而是要等待获取系统执行锁,即:竞争的start()所关联的那个系统锁。这是什么线程执行run()之前要调用的。而例外是:main的主线程是不需要调用所谓的start()的,因而不存在所谓系统锁的竞争。即:main不需系统锁(执行m2()方法),而另外线程执行m1()时,先要通过
    start()来竞争系统锁,因而main的耗时是在取对象锁之前取系统锁的耗时当然少了[因为不需要系统锁,耗时当然少]
    ---这就是8楼的理解。
    2)错误之处:8楼对JAVA线程机制的内部没有真正搞清楚。即:
    main中的
    st.start();//开启线程
    核心在于:
    这个start()方法中竞争系统锁是在哪一个线程中做的?
    8楼正是在这一点是理解错误。他认为是在另外一个线程中竞争的。恰恰不是。它正是在main主线程中竞争的。即:start()的代码是在main主线程执行的!只有当开始执行run()中代码时,才由另外一个线程来执行。
    即:8楼的所谓的系统锁的竞争,是在main()中发生的。因而:所谓的系统锁的耗时是在main中的耗时,而当main在耗时时,另外一个线程还没有进入运行状态呢,还没有运行呢。[因为:start()还没有替它准备好线程的资源]。
      

  10.   

    答:因此:归纳结论就是:
    1)主线程main的启动是不需要start()这个同步方法的[即:所谓的那个什么“系统锁”--不需要获取]
    2)在main中创建的其它线程都要先运行start()这个同步方法的[即:所谓的那个什么“系统锁”--需要获取],而此时:这个start()同步方法是在main中运行的,所谓的系统锁的耗时是在main中的耗时,而不是在要运行的那个线程中耗时的。
    3)楼主的这个问题没什么意义:即:
    st.start();//开启线程
    st.m2();//
    内部执行过程是
    a)main主线程执行start()同步方法,准备线程资源。
    b)然后通过内部本地的c语言代码,准备在新的线程中开始执行run()中代码(CPU此时还在main主线程中),然后main()执行st.m2()。由于CPU此时还在main主线程中,还没有切换到另外一个新的线程中[切换需要时间],因而:在CPU上继续执行st.m2()的机会比需要通过切换CPU去执行m1()机会大。但这只是可能性,写程序最好不要依赖于这一点。