1、创建线程
在 Java 程序中创建线程有几种方法。每个 Java 程序至少包含一个线程:主线程。其它线程都是通过 Thread 构造器或实例化继续类 Thread 的类来创建的。
Java 线程可以通过直接实例化 Thread 对象或实例化继续 Thread 的对象来创建其它线程。在线程基础中的示例(其中,我们在十秒钟之内计算尽量多的素数)中,我们通过实例化 CalculatePrimes 类型的对象(它继续了 Thread),创建了一个线程。
当我们讨论 Java 程序中的线程时,也许会提到两个相关实体:完成工作的实际线程或代表线程的 Thread 对象。正在运行的线程通常是由操作系统创建的;Thread 对象是由 Java VM 创建的,作为控制相关线程的一种方式。
2、创建线程和启动线程并不相同
在一个线程对新线程的 Thread 对象调用 start() 方法之前,这个新线程并没有真正开始执行。Thread 对象在其线程真正启动之前就已经存在了,而且其线程退出之后仍然存在。这可以让您控制或获取关于已创建的线程的信息,即使线程还没有启动或已经完成了。
通常在构造器中通过 start() 启动线程并不是好主意。这样做,会把部分构造的对象暴露给新的线程。假如对象拥有一个线程,那么它应该提供一个启动该线程的 start() 或 init() 方法,而不是从构造器中启动它。
3、结束线程
线程会以以下三种方式之一结束:
线程到达其 run() 方法的末尾。
线程抛出一个未捕捉到的 Exception 或 Error。
另一个线程调用一个弃用的 stop() 方法。弃用是指这些方法仍然存在,但是您不应该在新代码中使用它们,并且应该尽量从现有代码中除去它们。
当 Java 程序中的所有线程都完成时,程序就退出了。
4、加入线程
Thread API 包含了等待另一个线程完成的方法:join() 方法。当调用 Thread.join() 时,调用线程将阻塞,直到目标线程完成为止。
Thread.join() 通常由使用线程的程序使用,以将大问题划分成许多小问题,每个小问题分配一个线程。本章结尾处的示例创建了十个线程,启动它们,然后使用 Thread.join() 等待它们全部完成。
5、调度
除了何时使用 Thread.join() 和 Object.wait() 外,线程调度和执行的计时是不确定的。假如两个线程同时运行,而且都不等待,您必须假设在任何两个指令之间,其它线程都可以运行并修改程序变量。假如线程要访问其它线程可以看见的变量,如从静态字段(全局变量)直接或间接引用的数据,则必须使用同步以确保数据一致性。
在以下的简单示例中,我们将创建并启动两个线程,每个线程都打印两行到 System.out:
public class TwoThreads {
public static class Thread1 extends Thread {
public void run() {
System.out.println("A");
System.out.println("B");
}
}
public static class Thread2 extends Thread {
public void run() {
System.out.println("1");
System.out.println("2");
}
}
public static void main(String[] args) {
new Thread1().start();
new Thread2().start();
}
}
我们并不知道这些行按什么顺序执行,只知道“1”在“2”之前打印,以及“A”在“B”之前打印。输出可能是以下结果中的任何一种:
1 2 A B
1 A 2 B
1 A B 2
A 1 2 B
A 1 B 2
A B 1 2
不仅不同机器之间的结果可能不同,而且在同一机器上多次运行同一程序也可能生成不同结果。永远不要假设一个线程会在另一个线程之前执行某些操作,除非您已经使用了同步以强制一个特定的执行顺序。
6、休眠
Thread API 包含了一个 sleep() 方法,它将使当前线程进入等待状态,直到过了一段指定时间,或者直到另一个线程对当前线程的 Thread 对象调用了 Thread.interrupt(),从而中断了线程。当过了指定时间后,线程又将变成可运行的,并且回到调度程序的可运行线程队列中。
假如线程是由对 Thread.interrupt() 的调用而中断的,那么休眠的线程会抛出 InterruptedException,这样线程就知道它是由中断唤醒的,就不必查看计时器是否过期。
Thread.yield() 方法就象 Thread.sleep() 一样,但它并不引起休眠,而只是暂停当前线程片刻,这样其它线程就可以运行了。在大多数实现中,当较高优先级的线程调用 Thread.yield() 时,较低优先级的线程就不会运行。
CalculatePrimes 示例使用了一个后台线程计算素数,然后休眠十秒钟。当计时器过期后,它就会设置一个标志,表示已经过了十秒。
7、守护程序线程
我们提到过当 Java 程序的所有线程都完成时,该程序就退出,但这并不完全正确。隐藏的系统线程,如垃圾收集线程和由 JVM 创建的其它线程会怎么样?我们没有办法停止这些线程。假如那些线程正在运行,那么 Java 程序怎么退出呢?
这些系统线程称作守护程序线程。Java 程序实际上是在它的所有非守护程序线程完成后退出的。
任何线程都可以变成守护程序线程。可以通过调用 Thread.setDaemon() 方法来指明某个线程是守护程序线程。您也许想要使用守护程序线程作为在程序中创建的后台线程,如计时器线程或其它延迟的事件线程,只有当其它非守护程序线程正在运行时,这些线程才有用。
8、示例:用多个线程分解大任务
在这个示例中,TenThreads 显示了一个创建了十个线程的程序,每个线程都执行一部分工作。该程序等待所有线程全部完成,然后收集结果。
/**
* Creates ten threads to search for the maximum value of a large matrix.
* Each thread searches one portion of the matrix.
*/
public class TenThreads {
private static class WorkerThread extends Thread {
int max = Integer.MIN_VALUE;
int[] ourArray;
public WorkerThread(int[] ourArray) {
this.ourArray = ourArray;
}
// Find the maximum value in our particular piece of the array
public void run() {
for (int i = 0; i < ourarray.length; i++)
max = Math.max(max, ourArray[i]);
}
public int getMax() {
return max;
}
}
public static void main(String[] args) {
WorkerThread[] threads = new WorkerThread[10];
int[][] bigMatrix = getBigHairyMatrix();
int max = Integer.MIN_VALUE;
// Give each thread a slice of the matrix to work with
for (int i=0; i < 10; i++) {
threads[i] = new WorkerThread(bigMatrix[i]);
threads[i].start();
}
// Wait for each thread to finish
try {
for (int i=0; i < 10; i++) {
threads[i].join();
max = Math.max(max, threads[i].getMax());
}
}
catch (InterruptedException e) {
// fall through
}
System.out.println("Maximum value was " + max);
}
}
9、小结
就象程序一样,线程有生命周期:它们启动、执行,然后完成。一个程序或进程也许包含多个线程,而这些线程看来互相单独地执行。
线程是通过实例化 Thread 对象或实例化继续 Thread 的对象来创建的,但在对新的 Thread 对象调用 start() 方法之前,这个线程并没有开始执行。当线程运行到其 run() 方法的末尾或抛出未经处理的异常时,它们就结束了。
sleep() 方法可以用于等待一段特定时间;而 join() 方法可能用于等到另一个线程完成。
分享到:
相关推荐
Java多线程生命周期的讲解,很详细,希望能帮到大家
Java线程状态流转图是一种用于描述Java线程生命周期中不同的状态和状态转换的图形表示方式。该图形展示了Java线程从创建到终止的整个生命周期,并详细介绍了每种状态的特点和转换规则。 NEW(初始化状态) 在Java...
### Java线程生命周期 Java线程有五种基本状态:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Terminated)。线程的状态会随着程序的运行而变化: 1. **新建**:当创建了一个新的线程...
本文将深入探讨Java线程的概念、生命周期、实现方式以及相关的同步机制。 首先,理解线程的基本概念至关重要。线程是程序中一个单一的顺序控制流,它在程序的上下文中运行,但具有独立的执行路径。多线程则是指在...
本资源"JAVA线程学习(源代码)"提供了关于Java线程的源代码示例,帮助我们深入理解和实践线程的使用。 首先,我们要理解Java中的线程模型。Java线程由`java.lang.Thread`类或`java.util.concurrent.Executor`框架来...
#### 五、Java线程的生命周期 Java线程的状态可以分为新建、就绪、运行、阻塞和死亡五个阶段。 - **新建状态**:当使用`new`关键字创建一个线程对象后,该线程处于新建状态。 - **就绪状态**:调用`start()`方法后...
在Java中,线程的生命周期包含五个基本状态,分别是新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)和死亡状态(Dead)。了解这些状态对于掌握Java多线程编程至关重要。 新建...
Java线程是多任务编程中的核心概念,它允许程序同时执行多个不同的任务,极大地提高了程序的效率和响应性。在Java中,线程是程序执行的最小单元,每个线程都有自己的程序计数器、虚拟机栈、本地方法栈和一部分堆内存...
Java线程有五种基本状态:新建(New)、可运行(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Terminated)。这些状态之间的转换是通过调用特定的方法,如start()、sleep()、join()、wait()、notify()等...
ExecutorService允许我们创建线程池,有效地管理线程生命周期,避免频繁创建和销毁线程的开销。ThreadPoolExecutor则允许我们自定义线程池的大小、线程存活时间等参数。Future接口代表异步计算的结果,可以用来检查...
### Java线程培训资料知识点详解 #### 一、Java线程基本概念 1. **如何编写与启动线程** - **方式一:继承Thread类** ```java class MyThread extends Thread { @Override public void run() { // 业务逻辑 ...
每个线程都有自己的生命周期,包括新建、就绪、运行、阻塞和结束五个状态。 2. **创建线程的方式**: - 继承`Thread`类:创建一个新的类,继承自`Thread`,重写`run()`方法,然后创建该类的实例并调用`start()`...
Java线程与并发编程实践是Java开发者必备的技能之一,特别是在多核处理器和高并发应用环境中,有效地管理和利用线程能极大地提升程序的性能。本书《java线程与并发实践编程》由Jeff Friesen撰写,2017年2月出版,...
线程的生命周期包括新建、就绪、运行、阻塞和终止等状态,理解这些状态以及如何在这些状态之间转换是理解和使用Java线程的基础。 书中可能涵盖了以下几个关键知识点: 1. **线程的创建与启动**:通过创建Thread...
- **线程的生命周期**:Java线程的生命周期包括NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(定时等待)和TERMINATED(终止)等状态。 - **线程同步机制**:为了防止多个线程对共享资源...
《Java线程实战手册》是Java并发编程领域的一份重要参考资料,主要针对Java开发者,旨在帮助他们深入理解和熟练掌握Java中的多线程技术。虽然这里只提供了第一章的内容,但这一章通常会涵盖基础理论和核心概念,对于...
Java 线程状态转换图 ...* 终止状态的线程对象已经结束生命周期,不能再次启动。 Java 线程状态转换图描述了线程在不同的状态之间的转换关系,了解这些状态和转换关系对 Java 编程的理解和应用非常重要。
3. `newCachedThreadPool()`: 创建一个可缓存的线程池,当线程空闲超过60秒,线程会自动终止,适合处理大量短生命周期的任务。 4. `newScheduledThreadPool(int corePoolSize)`: 创建一个定长的线程池,支持定时及...
线程的生命周期始于新建,通过调用start()方法进入就绪状态,然后可能进入运行、阻塞或等待,最后在run()方法执行完毕后死亡。 9.2 Thread的子类创建线程: 创建线程的一种方式是创建Thread类的子类,并重写run()...
Java线程有10个优先级,从`MIN_PRIORITY`(1)到`MAX_PRIORITY`(10),默认是`NORM_PRIORITY`(5)。优先级高的线程更可能被调度执行,但不保证。 4. **线程同步** 当多个线程访问共享资源时,可能会出现竞态条件,...