线程基础
线程(Thread)是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。
1. 基本概念
1.1 进程与线程
| 概念 | 说明 |
|---|---|
| 进程 | 程序的一次执行过程,是系统运行程序的基本单位 |
| 线程 | 比进程更小的执行单位,一个进程可以包含多个线程 |
主要区别:
| 特性 | 进程 | 线程 |
|---|---|---|
| 资源分配 | 独立的内存空间 | 共享进程的内存空间 |
| 通信方式 | IPC(管道、消息队列等) | 直接读写共享变量 |
| 切换开销 | 大(需要切换内存空间) | 小(同一进程内切换) |
| 独立性 | 相互独立 | 共享进程资源 |
2. 创建线程的方式
方式一:继承 Thread 类
java
public class MyThread extends Thread {
@Override
public void run() {
System.out.println("线程运行中: " + Thread.currentThread().getName());
}
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动线程
}
}特点:
- 简单直接
- Java 单继承限制,无法继承其他类
- 线程与任务耦合
方式二:实现 Runnable 接口(推荐)
java
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("线程运行中: " + Thread.currentThread().getName());
}
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.start();
// 使用 Lambda 表达式(Java 8+)
Thread thread2 = new Thread(() -> {
System.out.println("Lambda 线程运行中");
});
thread2.start();
}
}特点:
- 任务与线程分离,更灵活
- 可以继承其他类
- 同一个 Runnable 可被多个线程共享
- 推荐使用
方式三:实现 Callable 接口(可返回值)
java
import java.util.concurrent.*;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "任务执行完成";
}
public static void main(String[] args) throws Exception {
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
Thread thread = new Thread(futureTask);
thread.start();
// 获取返回值(会阻塞直到完成)
String result = futureTask.get();
System.out.println(result);
}
}特点:
- 可以返回执行结果
- 可以抛出异常
- 需要配合 FutureTask 使用
三种方式对比
| 方式 | 返回值 | 异常处理 | 继承限制 | 推荐度 |
|---|---|---|---|---|
| 继承 Thread | ❌ | ❌ | 有 | ⭐⭐ |
| 实现 Runnable | ❌ | ❌ | 无 | ⭐⭐⭐⭐ |
| 实现 Callable | ✅ | ✅ | 无 | ⭐⭐⭐⭐⭐ |
3. 线程生命周期
3.1 六种状态
start()
NEW ──────────────► RUNNABLE ◄───────────────┐
│ │
│ │
┌─────────┼─────────┐ │
│ │ │ │
▼ ▼ ▼ │
BLOCKED WAITING TIMED_WAITING ──┘
│ │ │
└─────────┼─────────┘
│
▼
TERMINATED| 状态 | 说明 | 触发条件 |
|---|---|---|
NEW | 新建状态 | 线程被创建但尚未调用 start() |
RUNNABLE | 可运行状态 | 调用 start() 后,包括就绪和运行中 |
BLOCKED | 阻塞状态 | 等待获取 synchronized 锁 |
WAITING | 等待状态 | 调用 wait()、join()、LockSupport.park() |
TIMED_WAITING | 超时等待 | 调用 sleep(n)、wait(n)、join(n) |
TERMINATED | 终止状态 | 线程执行完毕或异常退出 |
3.2 状态转换方法
java
// NEW → RUNNABLE
thread.start();
// RUNNABLE → TIMED_WAITING
Thread.sleep(1000);
// RUNNABLE → WAITING
object.wait();
thread.join();
// WAITING/TIMED_WAITING → RUNNABLE
object.notify();
object.notifyAll();
// RUNNABLE → BLOCKED
synchronized (lock) { ... } // 等待获取锁
// RUNNABLE → TERMINATED
// run() 方法执行完毕4. 常用方法
4.1 Thread 类方法
| 方法 | 说明 |
|---|---|
start() | 启动线程 |
run() | 线程执行体(不要直接调用) |
sleep(long ms) | 让线程休眠指定毫秒 |
join() | 等待该线程结束 |
interrupt() | 中断线程 |
isInterrupted() | 判断线程是否被中断 |
setName(String) | 设置线程名称 |
setPriority(int) | 设置线程优先级(1-10) |
setDaemon(boolean) | 设置为守护线程 |
4.2 示例代码
java
public class ThreadMethodDemo {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
if (Thread.currentThread().isInterrupted()) {
System.out.println("线程被中断,退出");
return;
}
System.out.println("执行中: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 重新设置中断标志
return;
}
}
});
thread.setName("worker-thread");
thread.start();
Thread.sleep(2500);
thread.interrupt(); // 中断线程
thread.join(); // 等待线程结束
System.out.println("主线程结束");
}
}5. 守护线程
守护线程(Daemon Thread)是为其他线程服务的后台线程,当所有非守护线程结束时,JVM 会退出,守护线程也随之终止。
java
Thread daemon = new Thread(() -> {
while (true) {
System.out.println("守护线程运行中...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
});
daemon.setDaemon(true); // 必须在 start() 之前设置
daemon.start();典型应用:
- 垃圾回收线程(GC)
- 心跳检测线程
- 日志记录线程
⚠️ 注意:守护线程中不要执行 IO 操作或持有资源,因为它可能随时被终止。