这里的"主","子"线程只是一个幌子!楼主请注意!
在main()方法中,虽然new 一个thread,但并没有真正启动该线程!真正启动线程应该调用t.start()!此处调用的是t.run(),jvm并不会以线程方式启动线程"t"!
所以此段代码永远不会输出pingpong,只会输出pongping!
==============
当代码中的t.run()变成t.start(),结果如何呢?我们将代码稍微改一点点:
public class test{
public static synchronized void main(string args[]){
thread t=new thread(){
public void run(){
pong();
}
};
t.start();
int i = 0;
while(i < 50){
i++;
try {
system.out.println(">>>a "+"astate="
+thread.currentthread().getstate()
+" bstate="+t.getstate());
thread.sleep(10);
} catch (interruptedexception e) {
}
}
}
static synchronized void pong(){
int i = 0;
while(i < 50){
i++;
try {
system.out.println("<<
thread.sleep(10);
} catch (interruptedexception e) {
}
}
}
}
这时我们可以看到,只能等主线程完全执行完毕以后,才会执行线程t.同时我们看到当主线程执行时,线程t的状态一直为blocked(阻塞).
那么为什么主线程执行时,t线程一直被阻塞呢?这就是main方法和pong方法前的synchronized 修饰词在作怪.
首先我们得了解synchronized 修饰词的作用,但了解synchronized的同时,我们还得了解lock(锁).java中规定,每个对象有且仅有一个锁,这个锁是jvm自动维护的,不需要显示去定义.
另外synchronized只是在多线程同时工作时起作用.
那么synchronized修饰词就说了,访问我这个方法(或这段代码)必须要单独执行,也就是说,想要执行我,就得把某个东西给锁上,这就是你想执行我的代价.
把某个东西锁上,锁谁呢?前面说了,每个对象都有一把锁啊?那么这个被锁的对象就得根据synchronized修饰的位置而定了.
且只拿你的这段代码来说明:
此test类有两个static方法,而这两个static方法前都加了synchronized的修饰.如果synchronized加在static方法前,就表明线程在访问这个方法时,会自动锁住此方法"所在类的类对象"(java秉承万物皆对象的宗旨,类本身也不例外).比如main()方法和pong()方法,他们的synchronized就表明在访问它们的时候,会锁住test.class对象.
好,知道了原理再来理解就很容易啦!
首先主线程来执行入口方法(即main()),但main()前有synchronized关键字,这时候主线程就会给test.class上锁.然后继续执行,一直很顺利的执行,直到遇见t.start().这个时候,主线程会通过t.start()方法通知jvm:要开一个新线程啦,我已经把它给准备好啦! 然而主线程就只是在这里通知一下而已,它不会等待t线程真正开始,事实上它根本不关心t线程的死活.好啊,jvm收到了通知,就做了一系列准备,要来启动t线程,然后费了九牛二虎之力把它给启动了.t线程也开始执行了.t线程的任务是做什么呢?就是执行pong()方法.当它想执行pong()方法时,发现pong()方法是静态的,而且前面还有synchronized修饰符,它就必须得先给test.class上锁啊,只有锁住test.class才能有权力执行pong()方法.结果t线程来锁test.class对象的时候,发现该对象已经被锁了!原来是前面主线程在执行main()方法时锁住的.那么t线程就只能等啦!于是它就blocked了.
主线程呢,在通知jvm启动t线程之后,它就继续往下执行了,这里我改了代码,会输出50行字符,每输出一行就会休息10毫秒.于是主线程就按照这种方式工作下去.50行字符输出完了,main()方法也就执行完了,于是就将之前锁住的test.class给开锁了.这时候在一旁等待的t线程发现test.class解锁啦!于是它立马又将其锁住,开始执行它的pong()方法了.