Java 多线程编程精通:高效并发编程实战指南
Java 是一门 多线程编程语言,意味着我们可以用 Java 开发多线程程序。多线程程序包含两个或更多可并发运行的部分,每部分可同时处理不同任务,从而最优利用可用资源,特别是当计算机有多个 CPU 时。
按定义,多任务是指多个进程共享 CPU 等通用处理资源。多线程将多任务的概念扩展到应用程序内部,可将单个应用中的特定操作细分为独立线程。每个线程可并行运行。操作系统不仅在不同应用间分配处理时间,也在应用内的各线程间分配。
多线程使你能以多活动在同一程序中并发进行的方式编写代码。
线程生命周期
线程在其生命周期中会经历多个阶段。例如,线程诞生、启动、运行,最终终止。下图展示了线程的完整生命周期。
生命周期阶段如下:
新建 —— 新线程开始于新建状态。直到程序启动线程前一直保持此状态。也称为 出生线程。
可运行 —— 新建线程启动后变为可运行。此状态下线程被视为正在执行任务。
等待 —— 线程有时会转入等待状态,等待另一线程执行任务。仅当另一线程通知该等待线程继续执行时,才会转回可运行状态。
超时等待 —— 可运行线程可在指定时间间隔内进入超时等待状态。当时间间隔到期或等待的事件发生时,线程转回可运行状态。
终止 —— 可运行线程在完成任务或以其他方式终止时进入终止状态。
线程优先级
每个 Java 线程都有优先级,帮助操作系统确定线程调度顺序。
Java 线程优先级范围在 MIN_PRIORITY(常量 1)和 MAX_PRIORITY(常量 10)之间。默认每个线程优先级为 NORM_PRIORITY(常量 5)。
高优先级线程对程序更重要,应在低优先级线程前获得处理器时间。但线程优先级不能保证执行顺序,且高度依赖平台。
通过实现 Runnable 接口创建线程
若类旨在作为线程执行,可通过实现 Runnable 接口实现。需遵循三个基本步骤:
步骤 1
首先实现 Runnable 接口提供的 run() 方法。此方法为线程入口点,完整业务逻辑放在此方法中。run() 方法简单语法:
public void run()
步骤 2
其次,使用以下构造器实例化 Thread 对象:
Thread(Runnable threadObj, String threadName);
其中,threadObj 是实现 Runnable 接口的类实例,threadName 是新线程名称。
步骤 3
Thread 对象创建后,调用 start() 方法启动,这会执行 run() 方法调用。start() 方法简单语法:
void start();
示例
下例创建新线程并启动运行:
在线演示class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo(String name) {
threadName = name;
System.out.println("创建 " + threadName);
}
public void run() {
System.out.println("运行 " + threadName);
try {
for(int i = 4; i > 0; i--) {
System.out.println("线程: " + threadName + ", " + i);
// 让线程休眠片刻
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("线程 " + threadName + " 被中断。");
}
System.out.println("线程 " + threadName + " 退出。");
}
public void start() {
System.out.println("启动 " + threadName);
if (t == null) {
t = new Thread(this, threadName);
t.start();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo("Thread-1");
R1.start();
RunnableDemo R2 = new RunnableDemo("Thread-2");
R2.start();
}
}
输出结果如下:
输出
创建 Thread-1 启动 Thread-1 创建 Thread-2 启动 Thread-2 运行 Thread-1 线程: Thread-1, 4 运行 Thread-2 线程: Thread-2, 4 线程: Thread-1, 3 线程: Thread-2, 3 线程: Thread-1, 2 线程: Thread-2, 2 线程: Thread-1, 1 线程: Thread-2, 1 线程 Thread-1 退出。 线程 Thread-2 退出。
通过继承 Thread 类创建线程
创建线程的第二种方式是创建新类继承 Thread 类,仅需两步。此方式利用 Thread 类可用方法提供更灵活的多线程处理。
步骤 1
需重写 Thread 类中的 run() 方法。此方法为线程入口点,完整业务逻辑放在此方法中。run() 方法简单语法:
public void run()
步骤 2
Thread 对象创建后,调用 start() 方法启动,执行 run() 方法调用。start() 方法简单语法:
void start();
示例
下面是前面程序改写为继承 Thread 类的版本:
在线演示class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo(String name) {
threadName = name;
System.out.println("创建 " + threadName);
}
public void run() {
System.out.println("运行 " + threadName);
try {
for(int i = 4; i > 0; i--) {
System.out.println("线程: " + threadName + ", " + i);
Thread.sleep(50);
}
} catch (InterruptedException e) {
System.out.println("线程 " + threadName + " 被中断。");
}
System.out.println("线程 " + threadName + " 退出。");
}
public void start() {
System.out.println("启动 " + threadName);
if (t == null) {
t = new Thread(this, threadName);
t.start();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo("Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo("Thread-2");
T2.start();
}
}
输出结果如下:
输出
创建 Thread-1 启动 Thread-1 创建 Thread-2 启动 Thread-2 运行 Thread-1 线程: Thread-1, 4 运行 Thread-2 线程: Thread-2, 4 线程: Thread-1, 3 线程: Thread-2, 3 线程: Thread-1, 2 线程: Thread-2, 2 线程: Thread-1, 1 线程: Thread-2, 1 线程 Thread-1 退出。 线程 Thread-2 退出。
Thread 类常用方法
以下是 Thread 类中重要方法列表:
| 序号 | 方法及描述 |
|---|---|
| 1 | public void start() 在单独执行路径中启动线程,随后在此 Thread 对象上调用 run() 方法。 |
| 2 | public void run() 若此 Thread 对象是用单独 Runnable 目标实例化的,则在该 Runnable 对象上调用 run() 方法。 |
| 3 | public final void setName(String name) 更改 Thread 对象名称。也有 getName() 方法获取名称。 |
| 4 | public final void setPriority(int priority) 设置此 Thread 对象优先级。取值范围 1 到 10。 |
| 5 | public final void setDaemon(boolean on) 参数为 true 时将此 Thread 标记为守护线程。 |
| 6 | public final void join(long millisec) 当前线程在另一线程上调用此方法,导致当前线程阻塞,直到另一线程终止或指定毫秒数过去。 |
| 7 | public void interrupt() 中断此线程,使其在因任何原因阻塞时继续执行。 |
| 8 | public final boolean isAlive() 若线程存活则返回 true,即线程启动后但在运行完成前的任何时间。 |
上述方法在特定 Thread 对象上调用。Thread 类中以下方法为静态方法。调用静态方法时对当前运行线程执行操作。
| 序号 | 方法及描述 |
|---|---|
| 1 | public static void yield() 使当前运行线程让出 CPU,调度同优先级的其他等待线程。 |
| 2 | public static void sleep(long millisec) 使当前运行线程阻塞至少指定毫秒数。 |
| 3 | public static boolean holdsLock(Object x) 若当前线程持有给定对象的锁则返回 true。 |
| 4 | public static Thread currentThread() 返回对当前运行线程的引用,即调用此方法的线程。 |
| 5 | public static void dumpStack() 打印当前运行线程的堆栈跟踪,调试多线程应用时很有用。 |
示例
下面的 ThreadClassDemo 程序演示 Thread 类的部分方法。考虑实现 Runnable 的 DisplayMessage 类:
// 文件名:DisplayMessage.java
// 创建实现 Runnable 的线程
public class DisplayMessage implements Runnable {
private String message;
public DisplayMessage(String message) { this.message = message; }
public void run() {
while(true) { System.out.println(message); }
}
}
另一个继承 Thread 类的类:
// 文件名:GuessANumber.java
// 创建继承 Thread 的线程
public class GuessANumber extends Thread {
private int number;
public GuessANumber(int number) { this.number = number; }
public void run() {
int counter = 0, guess = 0;
do {
guess = (int) (Math.random() * 100 + 1);
System.out.println(this.getName() + " 猜测 " + guess);
counter++;
} while(guess != number);
System.out.println("** 正确!" + this.getName() + "在" + counter + "次猜测后。**");
}
}
使用上述类的主程序:
// 文件名:ThreadClassDemo.java
public class ThreadClassDemo {
public static void main(String[] args) {
Runnable hello = new DisplayMessage("Hello");
Thread thread1 = new Thread(hello);
thread1.setDaemon(true);
thread1.setName("hello");
System.out.println("启动 hello 线程...");
thread1.start();
Runnable bye = new DisplayMessage("Goodbye");
Thread thread2 = new Thread(bye);
thread2.setPriority(Thread.MIN_PRIORITY);
thread2.setDaemon(true);
System.out.println("启动 goodbye 线程...");
thread2.start();
System.out.println("启动 thread3...");
Thread thread3 = new GuessANumber(27);
thread3.start();
try { thread3.join(); } catch (InterruptedException e) { System.out.println("线程中断。"); }
System.out.println("启动 thread4...");
Thread thread4 = new GuessANumber(75);
thread4.start();
System.out.println("main() 结束...");
}
}
运行结果(每次运行结果不同):
输出
启动 hello 线程... 启动 goodbye 线程... Hello Hello Hello Hello Hello Hello Goodbye Goodbye Goodbye Goodbye Goodbye .......
Java 多线程核心概念
进行 Java 多线程编程时,需熟练掌握以下概念:
什么是线程同步?
线程间通信处理
线程死锁处理
主要线程操作
java
- 精通 C++ 多线程编程:高效并发开发实战
- C# 多线程编程精通:提升性能与效率的核心技术
- 精通 Java 运算符:类型、语法与实战示例
- Java 注释:类型、用法与最佳实践
- 精通 Java 增强 for 循环:语法、示例与最佳实践
- 精通 Java 字符串:创建、方法与最佳实践
- 精通 Java 接口:概念、实现与最佳实践
- 精通 Java 匿名内部类:定义、语法与实战示例
- 精通 Java Try-With-Resources:自动资源管理详解
- Java 注解详解:类型、放置位置与实战示例
- Java 断言实战指南:尽早发现 Bug 与保障代码可靠性
- 深入理解 Java Vector:用法、特性及与 ArrayList 的对比