java线程相关的方法
/ sleep() 会使线程进入 TIMED_WAITING// yield() 后线程仍是 RUNNABLEsleep()是强制暂停,有明确的时间控制,线程会进入等待状态。yield()是礼貌请求,仅是一个建议,调度器可以忽略,线程仍在运行状态。当一个 Java 程序启动时,JVM 会自动创建一个名为main的线程,即主线程。它是程序的入口点,负责执行方法。所有其他线程(用户线程或守护线程)通常
Thread
类的常用方法
方法名 | 说明 |
---|---|
start() |
启动新线程,JVM会调用该线程的 run() 方法。不能重复调用。 |
run() |
线程执行体。如果直接调用,不会开启新线程,而是在当前线程中执行。 |
sleep(long millis) |
静态方法,使当前线程休眠指定毫秒数,期间不释放锁。 |
sleep(long millis, int nanos) |
更精确的休眠,支持纳秒。 |
yield() |
静态方法,提示调度器当前线程愿意让出CPU,但不保证立即切换。 |
join() |
等待该线程执行完毕。 |
join(long millis) |
最多等待指定毫秒数,超时则继续执行。 |
join(long millis, int nanos) |
更精确的等待时间。 |
interrupt() |
中断线程。如果线程在 sleep 、wait 等阻塞状态,会抛出 InterruptedException 。 |
isInterrupted() |
判断线程是否被中断,不改变中断状态。 |
Thread.interrupted() |
静态方法,判断当前线程是否被中断,并清除中断状态。 |
isAlive() |
判断线程是否处于活动状态(已启动且未终止)。 |
getName() / setName(String name) |
获取/设置线程名。 |
getPriority() / setPriority(int priority) |
获取/设置线程优先级(1-10)。 |
setDaemon(boolean on) |
设置为守护线程(必须在 start() 前调用)。 |
currentThread() |
静态方法,返回当前正在执行的线程对象。 |
Object
类中的线程控制方法(用于线程间通信)
这些方法必须在同步上下文(synchronized)中调用,否则会抛出 IllegalMonitorStateException
。
方法名 | 说明 |
---|---|
wait() |
当前线程释放锁并进入等待状态,直到被 notify() 或 notifyAll() 唤醒。 |
wait(long timeout) |
等待指定时间,超时后自动唤醒。 |
wait(long timeout, int nanos) |
更精确的等待。 |
notify() |
唤醒在此对象监视器上等待的一个线程(随机)。 |
notifyAll() |
唤醒在此对象监视器上等待的所有线程。 |
sleep与yeild方法的区别
特性 | Thread.sleep(long millis) |
Thread.yield() |
---|---|---|
是否释放锁 | ❌ 不释放任何锁(如 synchronized 锁) | ❌ 不释放任何锁 |
是否进入阻塞状态 | ✅ 是,线程进入 TIMED_WAITING 状态 |
❌ 否,线程仍处于 RUNNABLE 状态 |
调度行为 | 当前线程暂停指定时间,时间到后重新竞争CPU | 提示调度器“我愿意让出CPU”,但不保证会立即让出 |
可预测性 | 高,休眠时间是明确的 | 低,完全依赖JVM和操作系统调度器 |
典型用途 | 控制执行频率、定时任务、模拟延迟 | 尝试优化多线程竞争(极少使用) |
Thread.sleep()
- 作用:使当前线程暂停执行指定的毫秒数(或纳秒),在此期间不参与CPU竞争。
- 状态变化:线程从
RUNNABLE
状态进入TIMED_WAITING
状态。 - 锁的持有:不释放任何已持有的锁。例如,在
synchronized
块中调用sleep()
,其他线程无法进入该同步块。 - 中断处理:如果线程在
sleep()
期间被中断(interrupt()
),会抛出InterruptedException
。
synchronized (lock) {
System.out.println("Thread is about to sleep");
Thread.sleep(2000); // 其他线程无法进入此同步块
System.out.println("Thread woke up");
}
Thread.yield()
- 作用:提示线程调度器当前线程愿意让出CPU,以便其他同优先级的线程有机会运行。
- 状态变化:线程仍处于
RUNNABLE
状态,只是调度器可能会选择其他线程执行。 - 锁的持有:不释放任何锁。
- 可预测性差:
yield()
的行为高度依赖JVM实现和操作系统调度策略。在某些JVM上,yield()
可能完全被忽略。 - 典型用途:几乎不推荐使用,因为效果不确定。在现代JVM中,调度器通常比开发者更懂得如何优化线程调度。
for (int i = 0; i < 1000; i++) {
// 高频循环,可能长时间占用CPU
if (i % 100 == 0) {
Thread.yield(); // 提示让出CPU,但不一定生效
}
}
总结
// sleep() 会使线程进入 TIMED_WAITING
Thread.sleep(1000);
System.out.println(thread.getState()); // TIMED_WAITING
// yield() 后线程仍是 RUNNABLE
Thread.yield();
System.out.println(thread.getState()); // RUNNABLE
sleep()
是强制暂停,有明确的时间控制,线程会进入等待状态。yield()
是礼貌请求,仅是一个建议,调度器可以忽略,线程仍在运行状态。
join方法实现线程间的同步
join()
方法是 Java 中 Thread
类提供的一个非常重要的方法,用于实现线程间的同步,确保一个线程等待另一个线程执行完毕后再继续执行。
join()
方法的三种形式
方法签名 | 说明 |
---|---|
void join() |
等待该线程无限期执行完毕。 |
void join(long millis) |
最多等待指定的毫秒数。如果超时,主线程不再等待。 |
void join(long millis, int nanos) |
更精确的等待时间(毫秒 + 纳秒)。 |
基本用法与示例
1. 基本 join()
:等待线程结束
Thread t1 = new Thread(() -> {
for (int i = 0; i < 3; i++) {
System.out.println("Thread-1: " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
System.out.println("Main thread starts");
t1.start();
t1.join(); // 主线程等待 t1 执行完毕
System.out.println("Main thread continues after t1 finished");
输出:
Main thread starts
Thread-1: 0
Thread-1: 1
Thread-1: 2
Main thread continues after t1 finished
✅ 效果:main
线程在 t1.join()
处阻塞,直到 t1
线程执行完 run()
方法后才继续。
join() 的底层原理
join() 方法的实现依赖于 wait() 和 notify() 机制:
- 当调用
t.join()
时,当前线程(如main
)会在这个线程对象t
上调用wait()
。 - 当线程
t
执行完毕(run()
方法结束),JVM 会自动调用t.notifyAll()
唤醒所有等待在t
上的线程。 - 因此,
join()
本质上是基于对象监视器的等待/通知机制。
join()
的典型应用场景
场景 | 说明 |
---|---|
主线程等待子线程完成 | 如:主线程启动多个数据处理线程,需等待全部完成后再汇总结果。 |
顺序执行多个线程 | 实现线程 A → B → C 的串行执行。 |
资源清理 | 确保后台线程完成清理工作后再退出程序。 |
interrupt()打断阻塞线程和打断运行线程
调用 thread.interrupt()
并不会强制终止线程,而是:
- 设置线程的中断状态(interrupt status)为
true
。 - 如果线程处于阻塞状态(如
sleep
、wait
、join
等),会立即抛出InterruptedException
,并清除中断状态(重置为false
)。
✅ 关键原则:中断是一种请求,线程是否响应、如何响应,由线程自身决定。
打断阻塞线程(Blocked Thread)
当一个线程正在执行可中断的阻塞方法时,调用 interrupt()
会立即中断该阻塞状态。
常见的可中断阻塞方法:
Thread.sleep(long millis)
Object.wait()
Thread.join()
BlockingQueue.put()/take()
Future.get()
Socket InputStream.read()
等
行为表现:
- 阻塞方法会立即抛出
InterruptedException
。 - 线程的中断状态被自动清除(变为
false
)。 - 程序流跳转到
catch
块,可以在此处处理中断逻辑(如退出循环)。
示例:中断 sleep()
中的线程
Thread t = new Thread(() -> {
try {
System.out.println("Thread is about to sleep");
Thread.sleep(5000); // 阻塞5秒
System.out.println("Thread woke up normally");
} catch (InterruptedException e) {
System.out.println("Thread was interrupted during sleep!");
System.out.println("Current interrupted status: " + Thread.currentThread().isInterrupted()); // false
// 通常在此处退出线程
}
});
t.start();
// 主线程等待1秒后中断 t
Thread.sleep(1000);
t.interrupt(); // 中断 t 线程
Thread is about to sleep
Thread was interrupted during sleep!
Current interrupted status: false
打断运行线程(Running Thread)
当一个线程正在执行普通代码(非阻塞)时,调用 interrupt()
只会设置其中断状态为 true
,不会抛出异常,线程会继续执行。
行为表现:
- 中断状态被设置为
true
。 - 线程继续执行,不受影响。
- 线程需要主动检查中断状态,并决定是否退出。
示例:中断一个正在运行的循环
Thread t = new Thread(() -> {
while (!Thread.currentThread().isInterrupted()) { // 主动检查中断状态
System.out.println("Thread is working...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("Interrupted while sleeping");
Thread.currentThread().interrupt(); // 重要:重新设置中断状态
break;
}
}
System.out.println("Thread is exiting gracefully.");
});
t.start();
Thread.sleep(2000);
t.interrupt(); // 设置中断状态为 true
Thread is working...
Thread is working...
Thread is working...
Thread is working...
Interrupted while sleeping
Thread is exiting gracefully.
主线程与守护线程
主线程(Main Thread)
1. 什么是主线程?
- 当一个 Java 程序启动时,JVM 会自动创建一个名为
main
的线程,即主线程。 - 它是程序的入口点,负责执行
public static void main(String[] args)
方法。 - 所有其他线程(用户线程或守护线程)通常由主线程创建。
2. 主线程的特点
特性 | 说明 |
---|---|
生命周期 | 属于用户线程(非守护线程) |
JVM 退出影响 | JVM 不会因为主线程结束而立即退出,只要还有用户线程在运行,JVM 就继续运行。 |
创建其他线程 | 主线程可以创建多个子线程(用户线程或守护线程)。 |
默认优先级 | 通常为 NORM_PRIORITY (5) |
3. 示例:主线程结束,但 JVM 不退出
public class MainThreadExample {
public static void main(String[] args) {
Thread worker = new Thread(() -> {
while (true) {
System.out.println("Worker thread is running...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
break;
}
}
});
worker.start();
System.out.println("Main thread is ending...");
// 主线程结束
}
}
输出:
Main thread is ending...
Worker thread is running...
Worker thread is running...
...
✅ 说明:即使 main
方法执行完毕,只要 worker
线程(用户线程)仍在运行,JVM 就不会退出。
守护线程(Daemon Thread)
1. 什么是守护线程?
- 守护线程是一种后台服务线程,为其他线程提供服务(如垃圾回收、JIT 编译等)。
- 它的存在与否不影响 JVM 的退出。
- 当 JVM 中所有用户线程结束时,无论还有多少守护线程在运行,JVM 都会自动退出。
2. 如何创建守护线程?
必须在调用 start()
之前,使用 setDaemon(true)
设置:
Thread daemonThread = new Thread(() -> {
while (true) {
System.out.println("Daemon thread is working...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
break;
}
}
});
daemonThread.setDaemon(true); // 必须在 start() 前设置
daemonThread.start();
⚠️ 注意:如果在 start()
之后调用 setDaemon(true)
,会抛出 IllegalThreadStateException
。
3. 守护线程的特点
特性 | 说明 |
---|---|
用途 | 执行后台任务,如监控、日志、定时清理等 |
JVM 退出 | 不阻止 JVM 退出。当所有用户线程结束,JVM 强制终止所有守护线程并退出。 |
资源清理 | 不能依赖守护线程进行资源清理(如关闭文件、释放数据库连接),因为它可能随时被终止。 |
默认线程 | JVM 自带的垃圾回收器(GC)、JIT 编译线程都是守护线程。 |
主线程与守护线程对比
特性 | 主线程(Main Thread) | 守护线程(Daemon Thread) |
---|---|---|
类型 | 用户线程(非守护) | 守护线程 |
创建者 | JVM 自动创建 | 程序员手动创建并设置 setDaemon(true) |
JVM 退出条件 | 只要有一个用户线程运行,JVM 就不退出 | 守护线程的存在不影响 JVM 退出 |
典型用途 | 程序入口、启动子线程 | 后台服务(监控、日志、定时任务) |
资源清理 | 可以安全进行 | 不能依赖,可能被强制终止 |
设置时机 | N/A | 必须在 start() 之前调用 setDaemon(true) |
- 主线程是程序的起点,属于用户线程,它的结束不意味着程序结束。
- 守护线程是后台服务线程,不阻止 JVM 退出。
- JVM 退出的唯一条件:所有用户线程都已终止。
- 正确使用守护线程可以提升程序的后台服务能力,但需注意其不可靠性,不能用于关键任务。
线程的状态
在Java中,线程的状态(Thread State)由 java.lang.Thread.State
枚举类定义,共有 6种状态。这些状态描述了线程在其生命周期中的不同阶段。
1. NEW
(新建)
- 线程被创建,但尚未调用
start()
方法。 - 此时线程对象已经存在,但还没有被JVM调度执行。
Thread t = new Thread(() -> {});
// 此时 t.getState() == Thread.State.NEW
2. RUNNABLE
(可运行)
- 线程已经启动,正在JVM中执行,或者正在等待操作系统资源(如CPU时间片)。
- 注意:
RUNNABLE
状态包括了操作系统层面的“就绪”和“运行”两种状态。 - 并不意味着线程正在运行,只是说它可以运行,等待CPU调度。
3. BLOCKED
(阻塞)
- 线程试图获取一个对象的监视器锁(monitor lock),但该锁被其他线程持有。
- 常见于
synchronized
代码块或方法的竞争。 - 例如:线程A持有锁,线程B尝试进入同步代码块 → B进入
BLOCKED
状态。
4. WAITING
(无限期等待)
- 线程无限期等待另一个线程执行特定操作。
- 进入方式:
Object.wait()
Thread.join()
LockSupport.park()
- 退出方式:只能由其他线程显式唤醒(如
notify()
、notifyAll()
)或被中断。
5. TIMED_WAITING
(限期等待)
- 线程在指定时间内等待,时间到后会自动恢复。
- 进入方式:
Thread.sleep(long millis)
Object.wait(long timeout)
Thread.join(long millis)
LockSupport.parkNanos()
,parkUntil()
- 不需要其他线程唤醒,超时后自动进入可运行状态。
6. TERMINATED
(终止)
- 线程的
run()
方法已经执行完毕,或者因异常退出。 - 线程生命周期结束,无法再次启动。
更多推荐
所有评论(0)