Thread类常见方法
方法名 | 功能说明 | 注意事项 |
---|---|---|
start() | 启动一个新线程,在新的线程运行 run 方法中的代码 | start 方法只是让线程进入就绪,里面代码不一定立刻运行(CPU 的时间片还没分给它)。每个线程对象的start方法只能调用一次,如果调用了多次会出现IllegalThreadStateException (start方法才是启动线程的方法,直接调用run方法是没有用的 ) |
run() | 新线程启动后会调用的方法 | 如果在构造 Thread 对象时传递了 Runnable 参数,则线程启动后会调用 Runnable 中的 run 方法,否则默认不执行任何操作(因为默认Thread类的run方法里面是没有任何代码的),但可以创建 Thread 的子类对象,来覆盖默认行为 |
join() | 等待线程运行结束 | 在一个线程的代码里面调用另一个线程的join方法时,当前线程会阻塞(即暂停执行),直到被join的线程完成其执行。(join方法会抛出InterruptedException异常,这表明当前线程在等待过程中被中断。因此,调用join方法时通常需要使用try-catch块来处理这个异常。) |
join(long n) | 等待线程运行结束,最多等待 n 毫秒 | 在一个线程的代码里面调用另一个线程的join方法时,当前线程会阻塞(即暂停执行),阻塞n毫秒,如果n毫秒内线程完成执行了,那么就阻塞到被join的线程执行完成 |
getId() 获取线程长整型的 id | id 唯一 | |
getName() | 获取线程名 | |
setName(String) | 修改线程名 | |
getPriority() | 获取线程优先级 | |
setPriority(int) | 修改线程优先级 | java中规定线程优先级是1~10 的整数,较大的优先级能提高该线程被 CPU 调度的机率 |
getState() | 获取线程状态 | Java 中线程状态是用 6 个 enum 表示,分别为:NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED |
isInterrupted() | 用于检查线程的中断状态 | 当一个正在运行的线程被中断时,它的中断状态会被设置为true。线程可以通过调用自身的interrupt()方法来请求中断,而其它线程则可以通过调用这个线程的interrupt()方法来中断它。(调用isInterrupted()方法不会清除打断标记 ) |
interrupt() | 打断线程 | 如果被打断的线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除打断标记 ;如果打断的线程是正在运行的线程,则会设置打断标记 ;正在park 的线程被打断,也会设置 打断标记 |
interrupted() | static 方法,判断当前线程是否被打断 | 会清除打断标记 |
isAlive() | 线程是否存活(还没有运行完毕) | 1、如果线程已经通过调用 start() 方法启动,并且尚未通过调用 run() 方法的结束或异常终止,那么 isAlive() 将返回 true;2、即使线程在执行过程中被中断(通过调用 interrupt() 方法),只要 run() 方法尚未完成,isAlive() 仍然会返回 true |
currentThread() | static方法 ,获取当前正在执行的线程 | |
sleep(long n) | static方法,让当前执行的线程休眠n毫秒,休眠时让出 cpu 的时间片给其它线程 | 1. 调用 sleep 会让 当前线程从 Running 进入 Timed Waiting 状态(阻塞) 2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException3. 睡眠结束后的线程未必会立刻得到执行4. 建议用 TimeUnit 的 sleep 代替 Thread 的 sleep 来获得更好的可读性 |
yield() | static方法,提示线程调度器让出当前线程对CPU的使用 | (此方法主要是为了测试和调试)1. 调用 yield 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程 2. 具体的实现依赖于操作系统的任务调度器 |
void setDaemon(boolean on) | 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出(这个方法必须在start方法之前调用) | 1、垃圾回收器线程就是一种守护线程。2、Tomcat 中的 Acceptor 和 Poller 线程都是守护线程,所以 Tomcat 接收到 shutdown 命令后,不会等待它们处理完当前请求 |
park线程(认识)
Park线程的定义
- 在Java中,当线程无法继续执行时,它会被暂时挂起,等待某种条件的到来再继续执行,这种状态被称为线程的Parking状态。LockSupport类提供了park()和unpark(Thread thread)这两个核心方法,用于实现线程的阻塞和解除阻塞。
Park线程的方法
- park()方法:
- 作用:使当前线程进入等待状态(阻塞),直到被唤醒或者中断。
- 调用方式:可以直接调用LockSupport.park()方法,使当前线程阻塞。
- unpark(Thread thread)方法:
- 作用:解除指定线程的阻塞状态,使其可以继续执行。
- 调用方式:通过调用LockSupport.unpark(Thread thread)方法,并传入需要解除阻塞的线程对象作为参数。
- park()方法:
Park线程的工作机制
- 线程阻塞:当线程调用park()方法时,它会检查自己的状态。如果状态允许线程继续执行,则线程会继续执行;否则,线程会被放入休眠状态,等待被唤醒。
- 线程唤醒:当其他线程调用unpark(Thread thread)方法,并传入需要唤醒的线程对象时,该线程会从休眠状态被唤醒,并检查自身状态。如果满足条件,则线程会立即恢复执行。
- 注意:
- 如果要执行打断的线程标记是true,LockSupport.park()方法失效。因为打断线程的标记为true,则说明当前线程已经处于阻塞了,所以无法执行LockSupport.park()方法。因此用Thread.currentThread().interrupted()判断当前线程标记,此方法最后会把标记刷回false
- park中断是WAITTING状态,可以通过线程的getState()方法查看。
终止模式之两阶段终止(两个阶段:准备阶段和终止阶段)
模式介绍:在一个线程 T1 中“优雅”地终止线程 T2。(这里的【优雅】指的是给 T2 一个料理后事的机会)
1. 错误思路
- 使用线程对象的 stop() 方法停止线程
- stop 方法会真正杀死线程,如果这时线程锁住了共享资源,那么当它被杀死后就再也没有机会释放锁,其它线程将永远无法获取锁
- 使用 System.exit(int) 方法停止线程
- 我们的目的仅是停止一个线程,但这种做法会让整个程序都停止
2. 正确思路
利用 isInterrupted方法:
调用isInterrupted()方法不会清除打断标记
- interrupt 可以打断正在执行的线程,无论这个线程是在 sleep,wait,还是正常运行。如果被打断的线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除打断标记 ;
如果打断的线程是正在运行的线程,则会设置打断标记 ;正在park 的线程被打断,也会设置 打断标记
- interrupt 可以打断正在执行的线程,无论这个线程是在 sleep,wait,还是正常运行。如果被打断的线程正在 sleep,wait,join 会导致被打断的线程抛出 InterruptedException,并清除打断标记 ;
线程类:
public class TPTInterrupt {
private Thread thread;
public void start(){
thread = new Thread(() -> {
while(true) {
Thread current = Thread.currentThread();
if(current.isInterrupted()) { // 如果当前线程被打断了
log.debug("料理后事");
break;// 跳出循环
}
try {
Thread.sleep(1000);
log.debug("将结果保存");
} catch (InterruptedException e) {
current.interrupt();// 重新设置打断标记
}
// 执行监控操作
}
},"监控线程");
thread.start();
}
public void stop() {
thread.interrupt();
}
}
- 调用线程方法:
public class test {
public static void main(String[] args) {
TPTInterrupt t = new TPTInterrupt();
t.start();
Thread.sleep(3500);
log.debug("stop");
t.stop();
}
}
模式使用场景:后台监控线程
- 场景描述:
- 有一个后台监控线程,每隔一段时间返回一次监控结果。
- 当需要停止监控时,需要确保线程能够优雅地终止,释放资源。
- 实现步骤:
- 准备阶段:设置一个中断标志或调用线程的interrupt()方法,通知线程准备停止运行。
- 终止阶段:线程在检测到中断标志或捕获到InterruptedException异常后,执行必要的清理工作(如释放资源、关闭连接等),然后真正终止线程。