按:本文的大量内容来源于文末所附的参考页面。百度百科的那篇对普通线程的描述较好,IBM 文库那篇对 Java 线程的原理介绍较好。
线程(Thread)是程序执行流的最小单元,在台湾也被称为「执行绪(執行緒)」,这个名称显然更加直观。线程有时被称为轻量级进程(Lightweight Process, LWP)
注:这几点来自百度百科的相关信息整理
Java 线程,本质上对应操作系统的本地线程(native thread),两者是一一对应的。Java 语言提供线程编程接口。在使用这些接口时,本质上也是对操作系统的线程进行操作,这里仅从 Java 的视角去讨论线程。
2.1 创建线程
Java 线程机制提供了一个统一的线程函数,该线程函数通过 Java 虚拟机调用 Java 线程方法 , 这是通过 Java 本地方法调用来实现的。
图:Java 线程创建调用关系图,参1
Java 线程的创建调用过程如上图所示,首先 , Java 线程的 start 方法会创建一个本地线程(通过调用 JVM_StartThread),由其再进一步调用 run 方法。Java 线程的 run 方法和普通方法其实没有本质区别,直接调用 run 方法不会报错,但是却是在当前线程执行,而不会创建一个新的线程。
可以通过以下两种方式创建线程实例:
1. 扩展 Thread 类
public class HelloThread1 extends Thread {
@Override
public void run() {
System.out.println("Thread started!" );
}
public static void main(String[] args) {
Thread t = new HelloThread1();
t.start();
}
}
2. 实现 Runnable 接口
public class HelloThread2 implements Runnable {
@Override
public void run() {
System. out.println("Thread invoked!" );
}
public static void main(String[] args) {
Thread t = new Thread(new HelloThread2());
t.start();
}
}
不管是用哪种方法创建线程,实际上都是要实现一个 run 方法的。 run 方法本质是上一个回调方法,由 start 方法新创建的线程会调用这个方法从而执行需要的代码。 run 方法并不是真正的线程函数,只是被线程函数调用的一个 Java 方法而已,和其他的 Java 方法没有什么本质的不同。这也回答了「为何新起线程,要调用 start 方法,而不能调用 run 方法?」的问题。
使用接口创建线程在编程实践中更为灵活,也用的最多,是通常情况下推荐的用法。
Java 线程是建立在系统本地线程之上的,是另一层封装。Java 的线程状态,比 Windows/Linux 这些 OS 的线程状态要简单很多。其面向 Java 开发者提供的接口存在以下的局限性:
1. Java 线程机制不能获取线程退出的返回值,因而无法检测线程是正常退出还是异常终止。
2. 线程的同步。Java 提供方法 Thread.join() 来等待一个线程结束,一般情况这就足够了,但一种可能的情况是,需要等待在多个线程上(比如任意一个线程结束或者所有线程结束才会返回),循环调用每个线程的 Join 方法是不可行的,这可能导致很奇怪的同步问题。
3. Java 线程机制不能提供真实的线程 ID。Thread.getID() 的返回值是一个简单的计数 ID,和操作系统的线程 ID 没有任何关系。
4. Java 没有提供方法来获取线程中某段代码的运行时间的统计结果。虽然可以自行使用计时的方法来实现(获取运行开始和结束的时间,然后相减 ),但由于存在多线程调度方法的原因,无法获取线程实际使用的 CPU 运算时间,因而必然是不准确的。
参考: