当我们用cmd中的java命令运行程序时,java.exe进程启动:
(1)首先,它会调用系统api分配进程的资源(进程是系统分配资源的最小单位)
(2)系统级别的C语言main方法会启动一个主线程(系统级别)(每个进程至少有一个线程存在,即主线程(C语言的主线程,他一旦退出,其他所有的线程都要退出)
(3)主线程会调用 initialize_JVM(C语言main方法中),initialize_JVM会初始化java虚拟机参数。
然后create_VM:根据初始化参数创建java虚拟机。
启动jvm内部的守护线程(后台线程):如垃圾回收线程等等
调用java代码中的main方法(启动java main线程) ----- 主线程在不同上下文语义中,代表c语言系统级别的主线程还是java级别的主线程,要根据语义来决定,一般java语义所说的都是java main线程。
这里又涉及到一个概念:上下文
下面看一段代码:
public static void main(String[] args) { //1
Thread t = new Thread(new Runnable() { //2
@Override //3
public void run() { //4
System.out.println(Thread.currentThread().getName()); //5
} //6
});
t,start();zhi //7
System.out.println(Thread.currentThread().getName()); //8
}
运行结果如下:
不难发现,它是先执行第8行在执行第6行 :这是因为主线程main在执行到行2后会先创建new Thread对象,然后创建new Runnable 对象,让后直接t跳到第7行start申请系统启动Thread_0线程,此时,由于main线程属于运行态,执行比较快,而java创建线程需要申请操作系统,进行系统级别的线程创建及申请系统调度(线程的创建非常耗时,申请系统的调度也需要一定的时间。所以main线程要比Thread_0先执行完。
若想要先输出Thread_0 可以使用join()方法或者yield()方法,都是加在第7行后面,第八行前面
yield():
while (Thread.activeCount() > 1){
Thread.yield();
}
意思是如果当前的活跃线程大于1(主线程不能退出),则将当前线程(main)由运行态转变为就绪态,直到Thread_0线程执行完毕
也可以用join方法:直接在78行之间加上t.join();意思是当前线程(main)阻塞等待线程引用对象t即Thead_0执行完毕.
join用法:
1.当前线程:代码执行所在行的线程
2.t线程:线程引用对象
3.当前线程进行阻塞(运行态-->阻塞态)等待满足一定条件,而t线程不做处理,继续执行
4.条件为:(传入的时间到了)如t.join(3000),则表示当前线程阻塞3000毫秒,如不传入时间,则等待线程引用对象执行完毕。
多线程的效率问题:最高效率和系统资源+线程数+单个线程执行的任务量 有关
使用多线程提高效率需要考虑的因素:
(1)所有的线程执行都是并发+并行
(2)线程创建,销毁比较耗时
(3)线程的调度有系统决定(线程越多,系统调度越频繁; 线程由就绪态转变为运行态也是有性能及时间消耗的
(4)单个线程运行的任务量