Java 中,线程的基本操作主要依赖于 java.lang.Thread 和 java.lang.Object 类提供的方法。这些方法能够控制线程的创建、运行、中止和通信。
Java 线程的基本方法
start
方法:启动线程。run
方法:线程执行的逻辑。sleep
方法:让线程暂停执行一段时间。wait
方法:让线程等待某个条件。notify
和notifyAll
方法:唤醒等待线程。yield
方法:让出线程执行权。interrupt
方法:中断线程。join
方法:等待另一个线程完成。setDaemon
方法:设置线程为守护线程。
1. start
方法
- 作用:用于启动一个线程,并调用线程的
run
方法。 - 说明:调用
start
方法后,线程进入就绪状态,由 JVM 调度执行。 - 注意:不能直接调用
run
方法来启动线程,否则它只是在当前线程中执行run
方法,而不会以并发方式运行。
示例代码:
Thread thread = new Thread(() -> {
System.out.println("Thread is running...");
});
thread.start(); // 启动线程
2. run
方法
- 作用:定义线程的执行逻辑。
- 说明:
run
方法包含线程的具体操作,但需通过start
方法才能真正以线程的形式运行。 - 注意:直接调用
run
方法不会创建新线程。
3. sleep
方法
- 作用:让当前线程暂停执行一段时间。
- 特性:
- 属于
Thread
类的静态方法。 - 不释放锁资源。
- 抛出
InterruptedException
异常。
- 属于
- 用途:用于实现定时或延迟操作。
示例代码:
try {
Thread.sleep(1000); // 暂停 1 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
4. wait
方法
- 作用:让线程进入等待状态,直到其他线程调用
notify
或notifyAll
方法。 - 特性:
- 属于
Object
类,而不是Thread
类。 - 必须在同步块或同步方法中调用,否则会抛出
IllegalMonitorStateException
。 - 会释放锁资源。
- 属于
- 用途:用于线程间的通信。
示例代码:
synchronized (obj) {
obj.wait(); // 当前线程等待
}
5. notify
和 notifyAll
方法
- 作用:唤醒一个或所有正在等待的线程。
- 特性:
- 属于
Object
类。 - 必须在同步块或同步方法中调用。
- 不释放锁,直到当前线程退出同步块。
- 属于
示例代码:
synchronized (obj) {
obj.notify(); // 唤醒一个等待线程
}
6. yield
方法
- 作用:让当前线程暂时放弃 CPU 执行权,使其他线程有机会运行。
- 特性:
- 是静态方法。
- 不一定会让出执行权,具体行为依赖于操作系统的线程调度器。
- 用途:用于优化线程的执行顺序。
示例代码:
Thread.yield();
7. interrupt
方法
- 作用:中断线程,即改变线程的中断状态。
- 特性:
- 如果线程正在阻塞(如
sleep
或wait
),会抛出InterruptedException
。 - 如果线程未阻塞,仅会设置中断标志位。
- 如果线程正在阻塞(如
- 用途:安全停止线程。
示例代码:
Thread thread = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Thread was interrupted!");
}
});
thread.start();
thread.interrupt(); // 中断线程
8. join
方法
- 作用:等待指定线程完成。
- 特性:
- 会阻塞当前线程,直到目标线程执行完毕。
- 可指定超时时间。
- 用途:实现线程的顺序执行。
示例代码:
Thread thread = new Thread(() -> {
System.out.println("Thread is running...");
});
thread.start();
try {
thread.join(); // 等待线程完成
} catch (InterruptedException e) {
e.printStackTrace();
}
9. setDaemon
方法
- 作用:将线程设置为守护线程。
- 特性:
- 守护线程会在所有非守护线程结束后自动停止。
- 必须在调用
start
方法前设置,否则会抛出异常。
示例代码:
Thread thread = new Thread(() -> {
while (true) {
System.out.println("Daemon thread running...");
}
});
thread.setDaemon(true);
thread.start();
sleep
和 wait
的区别
特性 | sleep | wait |
---|---|---|
所属类 | Thread 类 | Object 类 |
锁状态 | 不释放锁 | 释放锁 |
用途 | 暂停线程,主要用于时间控制 | 线程间通信 |
调用位置 | 可在任何地方调用 | 必须在同步块或同步方法中 |
恢复条件 | 时间结束或被中断 | 被 notify /notifyAll 唤醒 |
start
方法和 run
方法的区别
start
方法:- 用于启动线程,并调用线程的
run
方法。 - 线程进入就绪状态,由 JVM 调度。
- 用于启动线程,并调用线程的
run
方法:- 包含线程的执行逻辑。
- 如果直接调用
run
方法,则不会启动新线程,仅在当前线程中执行。
终止线程的 4 种方式
- 正常结束:线程执行完毕后自动退出。
- 标志位控制:通过一个标志变量来控制线程的运行状态。
volatile boolean running = true; Thread thread = new Thread(() -> { while (running) { // 执行任务 } }); running = false; // 停止线程
interrupt
方法:通过中断标志位来通知线程停止。- 停止方法(不推荐):调用
stop
方法,直接强制终止线程,可能导致资源释放不完整。
相关问题
1. Java 中的 notify
方法和 notifyAll
方法有什么区别?
notify
和 notifyAll
是 Object
类的方法,用于唤醒处于等待状态的线程。它们的主要区别如下:
特性 | notify | notifyAll |
---|---|---|
唤醒线程的数量 | 唤醒一个等待线程。 | 唤醒所有等待线程。 |
选择性 | 被唤醒的线程由 JVM 决定(随机选择)。 | 所有线程被唤醒后进入就绪状态,竞争锁。 |
使用场景 | 适用于有明确线程唤醒逻辑的场景。 | 适用于需要唤醒所有等待线程的场景。 |
效率 | 可能更高,因为只唤醒一个线程。 | 可能导致线程切换开销增加。 |
示例代码:
synchronized (obj) {
obj.notify(); // 唤醒一个等待线程
// 或者
obj.notifyAll(); // 唤醒所有等待线程
}
notify
常用于需要处理特定任务的单线程。notifyAll
常用于广播通知,适合多个线程需同时响应的情况。
2. 守护线程是什么?
为其他线程(用户线程)提供后台服务的线程。当所有用户线程结束运行后,JVM 会自动终止守护线程的运行。
特性
- 生命周期依赖用户线程:所有用户线程结束后,守护线程会自动结束。
- 主要用于后台任务:如垃圾回收、定时器等。
设置守护线程
使用 setDaemon(true)
方法将线程设置为守护线程,但必须在调用 start
方法之前设置。
示例
Thread daemonThread = new Thread(() -> {
while (true) {
System.out.println("Daemon thread running...");
}
});
daemonThread.setDaemon(true); // 设置为守护线程
daemonThread.start();
- 守护线程在 JVM 终止时不保证完成其任务。
- 不建议将关键业务逻辑放在守护线程中。
3. 如何安全地终止一个线程?
通过标志位控制
线程在运行过程中定期检查一个标志变量,当标志变量被修改时,线程主动退出。
class SafeStopThread extends Thread {
private volatile boolean running = true;
public void run() {
while (running) {
System.out.println("Thread is running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态
break;
}
}
}
public void stopThread() {
running = false;
}
}
SafeStopThread thread = new SafeStopThread();
thread.start();
thread.stopThread(); // 安全终止线程
interrupt
方法
interrupt
方法会通知线程中断,通过抛出 InterruptedException
或检查 Thread.isInterrupted()
方法处理终止逻辑。
Thread thread = new Thread(() -> {
try {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Thread is running...");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Thread was interrupted!");
}
});
thread.start();
thread.interrupt(); // 通知线程中断
使用任务框架(如 Future
或 ExecutorService
)
通过线程池管理线程,调用 shutdown
或 cancel
方法来终止任务。
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<?> future = executor.submit(() -> {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Task is running...");
}
});
// 停止任务
future.cancel(true);
executor.shutdown();
结合 join
等待线程结束
通过标志位配合 join
方法,等待线程主动退出后,主线程继续执行
Thread thread = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread is running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
});
thread.start();
thread.join(); // 等待线程结束