一、ID
ID是线程的唯一标识,不同线程不会重复
获取方法
使用getId()方法可以获取线程的ID
代码示例:
public class ThreadIdDemo {
public static void main(String[] args) {
new Thread(()-> System.out.println("该线程ID:" + Thread.currentThread().getId())).start();
}
}
二、线程生命周期的基本状态(State)
六种基本状态
NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞):由锁导致的
WAITING(无限等待)、TIMED_WAITING(超时等待/限时等待)、TERMINATED(终止)
| 状态 | 含义 | 如何进入 | 如何退出 | 典型场景 |
| 新建New | 线程对象已经创建,但尚未启动 | 通过new Thread()创建线程对象后 | 调用线程的start()方法 | Thread thread = new Thread(Runnable); |
| 可运行Runnable | 线程已启动,可能正在运行或正准备运行,等待CPU时间片 | 调用start()方法;从阻塞、从等待或超时等待中准备好重新竞争CPU | 获取CPU时间片开始执行;或因某些操作让出CPU或进入其他状态 | 等待操作系统调度执行 |
| 阻塞Blcoked | 线程因为尝试获取一个被其他线程持有的(synchroized)而未能成功 | 尝试进入一个被其他线程持有的synchronized同步块或方法时 | 当持有锁的线程释放锁,该线程便有机会获取锁并回到可运行状态 | 竞争synchronized锁 |
| 等待Waiting | 线程进入无限期等待,需要等待线程显示唤醒 | 调用Object.wait()、Thread.join()(无参)或LockSupport.park() | 被其他线程通过Object.notify()/notifyAll()或中断唤醒 | 线程间协调,等待某个条件成立 |
| 超时等待Timed Waiting | 线程进入有限期等待,可在指定时间后自动唤醒或提前被唤醒 | 调用Thread,sleep(long)、Object.wait(long)、Thread,join(long)等带超时参数的方法 | 等待时间到期;或被其他线程通过中断、notify()等方式提前唤醒 | 执行定时任务,或等待一段时间 |
| 终止Terminated | 线程执行完毕或因异常而结束 | run()方法正常执行结束;或执行过程中抛出了未捕获的异常 | 终止是最终状态,无法再转换到其他状态 | 任务完成 |
补充了解:
CPU时间片(Time Slice 或 Quantum)是分时操作系统分配给每个正在运行的进程或线程的一段极短的CPU时间。它是实现操作系统“同时”运行多个任务的关键机制。(此处的“同时”是一种假象)
获取方法
使用getState()方法可以获取线程的基本状态
代码示例:
public class ThreadStateDemo {
private static final Object lock = new Object(); //用于同步的锁对象
public static void main(String[] args) throws InterruptedException{
//1.NEW 状态:线程刚被创建,未调用start()
Thread newThread = new Thread();
System.out.println("当前状态" + newThread.getState()); //此语句可输出当前线程状态
//判断当前状态是否是NEW
System.out.println("NEW状态:" + (newThread.getState() == Thread.State.NEW));
//2.RUNNABLE 状态:线程启动后
Thread runnableThread = new Thread(()->{
while (!Thread.currentThread().isInterrupted()){
//空转,保持线程Alive
}
});
runnableThread.start(); //启动线程,线程启动后很快可能进入RUNNABLE状态
Thread.sleep(1000); //休眠1秒,让线程启动
//判断当前状态是否是RUNNABLE
System.out.println("RUNNABLE状态:" + (runnableThread.getState() == Thread.State.RUNNABLE));
//3.BLOCK 状态:由锁导致
Thread blockThread = new Thread(()->{
synchronized (lock){
try {
Thread.sleep(1000); //持有锁一段时间,让另一个线程阻塞
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread willBeBlockedThread = new Thread(()->{
//这个锁会尝试获取已被blockedThread持有的锁,从而进入BLOCKED状态
synchronized (lock){
System.out.println("willBeBlockedThread 获得了锁");
}
});
blockThread.start();
Thread.sleep(50); //确保blockedThread先启动并拿到锁
willBeBlockedThread.start();
Thread.sleep(50); //确保willBeBlockedThread已经开始并因获取不到锁而阻塞
//判断当前状态是否是BLOCKED
System.out.println("BLOCK 状态:" + (willBeBlockedThread.getState() == Thread.State.BLOCKED));
//4.WAITING 状态:无期限等待
Thread waitingThread = new Thread(()->{
synchronized (lock){
try {
lock.wait(); //调用wait()方法,释放锁并进入WAITING状态,de
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
waitingThread.start();
Thread.sleep(3000); //确保waitingThread启动并进入WAITING状态
//判断当前状态是否是WAITING
System.out.println("WAITING状态:" + (waitingThread.getState() == Thread.State.WAITING));
//唤醒waitingThread以便程序能够继续执行
synchronized (lock){
lock.notify();
}
//5.TIMED_WARNING 状态:显示等待
Thread timedWaitingThread = new Thread(()->{
try {
Thread.sleep(2000); //睡眠2秒,进入TIMED_WAITING状态
} catch (InterruptedException e) {
e.printStackTrace();
}
});
timedWaitingThread.start();
Thread.sleep(50); //确保timedWaitingThread启动并进入TIMED_WARNING状态
//判断当前状态是否是TIMED_WAITING
System.out.println("TIMED_WARNING状态:" + (timedWaitingThread.getState() == Thread.State.TIMED_WAITING));
//6.TERMINATED 状态:线程终止)
Thread terminatedThread = new Thread();
terminatedThread.start();
terminatedThread.join();
//判断当前状态是否是TERMINATED
System.out.println("TERMINATED状态:" + (terminatedThread.getState() == Thread.State.TERMINATED));
//等待所有演示线程结束
/**
* join()方法是 Thread类提供的一个实例方法,
* 它的核心作用是让当前线程(调用方)进入等待状态,直到目标线程(被调用方)执行完毕,
* 或者等待超过指定的时间(如果使用了超时参数)。
* 例如,在线程 A 的执行代码中调用了 threadB.join(),那么线程 A 会暂停下来,一直等到线程 B 运行结束,线程 A 才会继续执行后续代码
* 。
*/
blockThread.join();
willBeBlockedThread.join();
waitingThread.join();
timedWaitingThread.join();
}
}
结果:
三、获取和设置线程的名称(Name)
每个线程都有名称,默认格式为“Thread-" + 数字(例如 Thread-0,Thread-1)。
有两种方法:
1.构造方法:在创建线程时直接指定名称。
2.setName()方法:对已经创建的线程对象设置名称。
获取方法
使用getName()方法可以获取线程的名称
代码示例:
public class ThreadNamingDemo {
public static void main(String[] args) throws InterruptedException{
//方式1:通过Thread的构造方法设置线程名称(用Lambda表达式实现Runnable举例)
Thread thread1 = new Thread(()->{
System.out.println(Thread.currentThread().getName() + "正在执行任务1");
},"线程名称-1");
//方式2:使用setName方法设置线程名称
Thread thread2 = new Thread(()->{
System.out.println(Thread.currentThread().getName() + "正在执行任务2");
});
thread2.setName("线程名称-2");
System.out.println("thread1的名称:" + thread1.getName()); //获取线程1的名称
System.out.println("thread2的名称:" + thread2.getName()); //获取线程2的名称
thread1.start();
thread2.start();
//获取当前线程(main线程)的名称
System.out.println("mian方法所在线程名称:" + Thread.currentThread().getName()); //输出main
}
}
结果:

四、查看是否存活(Alive)
线程存活指的是线程已经被启动(start()),并且还没有执行完 run() 方法中的任务,即线程还在“工作”中,没有“退休”。
线程对象创建后(NEW 状态),但尚未调用 start()方法时,isAlive()返回 false。
调用 start()方法后,线程进入 RUNNABLE 状态,isAlive()返回 true。
线程的 run()方法执行完毕或线程因异常终止后(TERMINATED 状态),isAlive()返回 false。
获取方法
使用isAlive()方法可以获取线程是否存活的状态(true/false)
代码示例:
public class ThreadAliveDemo {
public static void main(String[] args) throws InterruptedException{
Thread thread = new Thread(()->{
try {
System.out.println(Thread.currentThread().getName() + "开始运行");
Thread.sleep(2000); //休眠2秒
System.out.println();
} catch (InterruptedException e) {
e.printStackTrace();
}
},"测试线程");
//线程未启动(现在是NEW状态)
System.out.println("线程启动前是否存活:" + thread.isAlive()); //输出:false
thread.start(); //启动线程,进入RUNNABLE状态
//线程启动后(现在是RUNNABLE状态)
System.out.println("线程启动后是否存活:" + thread.isAlive()); //输出:true
Thread.sleep(3000); //休眠三秒,确认线程已经执行完毕
System.out.println("线程运行结束后是否存活:" + thread.isAlive()); //输出:false
}
}
结果:

五、优先级(Priority)
线程优先级为线程调度器提供提示,理论上优先级高的线程更易获得CPU时间。Java中优先级范围为1 (MIN_PRIORITY) 到10 (MAX_PRIORITY),默认为5 (NORM_PRIORITY)。
一定要在启动线程前设置优先级(调用start()方法前)
优先级仅为调度器提供建议,并不保证执行顺序,实际执行受操作系统和JVM实现影响
高优先级线程倾向于获得更多CPU时间,但不保证总是先执行。
设置方法
使用setPriority()方法可以设置代码优先级
获取方法
使用isPriority()方法可以获取代码优先级
代码示例:
public class ThreadPriorityDemo {
private static void peformTask(){
String threadName = Thread.currentThread().getName();
int Priority = Thread.currentThread().getPriority();
System.out.println(threadName + "启动 | 优先级:" + Priority);
//模拟工作负载
for (int i = 1; i <= 3; i++) {
System.out.println(threadName + "执行步骤" + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println(threadName + "被中断");
Thread.currentThread().interrupt();
break;
}
}
System.out.println(threadName + "完成");
}
public static void main(String[] args) {
//打印线程默认优先级(一般是5)
System.out.println(Thread.currentThread().getName() + "线程默认优先级为:" + Thread.currentThread().getPriority());
Thread lowPriorityThread = new Thread(()->{
Thread.currentThread().setName("低优先级线程");
peformTask();
});
Thread highPriorityThread = new Thread(()->{
Thread.currentThread().setName("高优先级线程");
peformTask();
});
//设置优先级(1-10,数字越大优先级越高),必须在start()前就设置
lowPriorityThread.setPriority(Thread.MIN_PRIORITY); //优先级1
highPriorityThread.setPriority(Thread.MAX_PRIORITY); //优先级10
lowPriorityThread.start();
highPriorityThread.start();
}
}
结果:

六、获取和设置后台程序(Daemon)
Java 中的线程分为前台线程和后台线程(也称为守护线程,Daemon Thread)
前台线程:会阻止 Java 进程结束,即使 main方法执行完毕,只要还有前台线程在运行,JVM 也不会退出。
后台线程:是为其他线程提供服务的线程(如 JVM 的垃圾回收线程)。它不会阻止 Java 进程结束。当所有前台线程都结束时,后台线程会自动死亡。而且它必须在start()方法之前使用
设置方法
使用setDaemon()方法可以设置线程的前后台。
setDaemon(true)是设置为后台线程;
setDaemon(false)是设置为前台线程。
获取方法
使用isDaemon()方法可以查看线程的前后台(true/false)
代码示例:
public class DaemonThreadDemo {
public static void main(String[] args) throws InterruptedException{
//创建一个无限循环的后台线程
Thread daemonThread = new Thread(()->{
while (true){
System.out.println(Thread.currentThread().getName() + "后台线程 正在运行……");
try {
Thread.sleep(1000); //每秒打印一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"后台线程示例");
daemonThread.setDaemon(true); //必须在线程启动前设置为后台线程
//创建一个只运行3秒的前台线程
Thread userThread = new Thread(()->{
for (int i = 1; i < 3; i++) {
System.out.println(Thread.currentThread().getName() + "前台线程 运行了" + i + "秒" );
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},"前台线程示例");
System.out.println("daemonThread是否是后台线程" + daemonThread.isDaemon()); //输出:true
System.out.println("userThread是否是后台线程" + userThread.isDaemon()); //输出:false
daemonThread.start();
userThread.start();
userThread.join(); //主线程等待userThread执行完毕
System.out.println(Thread.currentThread().getName() + "主线程结束");
// 此时只有后台线程daemonThread还在运行,但因为它是后台线程,JVM会强制终止它,进程结束。
}
}
结果:

七、中断(Interruption)
线程中断是一种协作机制,它允许一个线程通知另一个线程“你最好停下来”,但并不会强制立即终止目标线程。目标线程需要自行检查中断状态并决定如何响应。
这种机制提供了更大的灵活性,让线程有机会进行必要的清理工作,从而更安全地结束任务。
| 方法名 | 所属类型 | 功能描述 | 是否会清楚中断状态标志 |
| interrupt() | 非静态方法 | 给线程一个中断标志,设置中断状态为true,而不是停止线程。若线程正阻塞(如sleep),则会抛出InterruptedException异常 | 否 |
| isInterrupted() | 非静态方法 | 检查指定线程的中断状态(true/false)。 | 否 |
| interrupted() | 静态方法 | 检查当前线程的中断状态,并在检查后将中断状态清除为false | 是 |
| 线程状态或操作 | interrupt()的行为 | 中断标志位变化 | 注意事项 |
| 正常运行 | 仅设置中断标志为true,线程不会停止,需要自行检查标志位。 | 设置为true | 线程需主动检查isInterrupted()以响应中断 |
| sleep()、wait()、join() | 抛出InterruptedException异常,并清除中断标志位(设为false) | 清除为false | 需在catch块中通常应恢复中断状态 |
| LockSupport,park() | 线程会退出阻塞状态,不会抛出InterruptedException,但会保留中断标志 | 保持为true | 适用于更底层的线程控制 |
| 同步阻塞(synchronized) | 不会响应中断,线程会继续等待锁 | 无变化(仍为true,但在此场景下不直接起作用) | 需在获取锁后检查中断状态 |
| I/O操作 | 多数传统阻塞式I/O不响应中断 | 无变化(设置为true,但操作本身不中断) | 需使用Java NIO的可中断通道机制 |
代码示例:
public class ThreadInterruptLambdaDemo {
public static void main(String[] args) {
//创建一个可中断的工作线程
Thread workerThread = new Thread(()->{
Thread.currentThread().setName("工作线程");
System.out.println(Thread.currentThread().getName() + "开始工作");
//检查中断状态,决定是否继续执行
while (!Thread.currentThread().isInterrupted()){
//若中断,则工作线程标记为true,不执行该while循环;若没有中断,则执行该while循环
System.out.println("工作中……");
}
//退出循环后查看状态
System.out.println("循环退出后的中断状态:" + Thread.currentThread().isInterrupted());
//检查并清除中断状态
System.out.println("第一次调用interrupted():" +Thread.interrupted()); //返回true并清除标记
System.out.println("第二次调用interrupted():" +Thread.interrupted()); //再次调用,返回false
System.out.println("线程自然结束");
});
workerThread.start();
// 让主线程休眠1秒,确保工作线程能运行一段时间
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
workerThread.interrupt();
System.out.println("主线程已发出中断信号");
}
}
结果:

工作一会后


3215

被折叠的 条评论
为什么被折叠?



