## 一、线程名称 #### 1、设置名称 setName() 设置的时候需要在线程实例化后和线程启动前进行命名。 ``` Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.start(); ``` #### 2、获取名称 getName() 若在线程外获取名称则直接调用`线程对象.getName()`即可 若在线程内获取名称则需要用到`Thread.currentThread().getName()`进行获取 ```java public class DemoRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 20000; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } ``` ## 二、线程是否存活 使用方法`.isAlive()`,若存活则返回true。 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.start(); System.out.printf("%s是否存活:%s\n", t1.getName(), t1.isAlive());// 线程是否存活 try { Thread.sleep(2000); System.out.printf("%s是否存活:%s\n", t1.getName(), t1.isAlive());// 线程是否存活 } catch (InterruptedException e) { System.out.println(e.getMessage()); } ``` ## 三、线程优先级 #### 1、设置优先级 setPriority() 使用方法`.setPriority()`设置1~10的优先级,优先级越高线程越先运行 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.setPriority(1);// 设置1~10的优先级 Thread t2 = new Thread(new DemoRunnable()); t2.setName("线程2"); t2.setPriority(10);// 设置1~10的优先级 t1.start(); t2.start(); ``` 运行时虽然线程1比线程2先执行,但输出结果为线程2先输出 #### 2、获取优先级 getPriority() 返回`int`类型的1~10优先级。 ## 四、合并线程 `join()`的作用是**等待目标线程执行终止**,即将两个交替运行的线程合并成一个顺序运行的线程。 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.setPriority(1);// 设置1~10的优先级 Thread t2 = new Thread(new DemoRunnable()); t2.setName("线程2"); t2.setPriority(10);// 设置1~10的优先级 t1.start(); try { t1.join(); } catch (InterruptedException e) { System.out.println(e.getMessage()); } t2.start(); System.out.printf("%s是否存活:%s\n", t1.getName(), t1.isAlive());// 线程是否存活 ``` 上述代码中虽然线程1的优先级远低于线程2,但因在两个线程之间执行了`t1.join()`,将t1线程与主线程合并,所以主线程等待t1线程运行结束后才会执行`t2.start()`。 ## 五、线程让行 `yield()`方法**提示调度器**当前线程愿意让出CPU,仅对优先级相同的线程有效。 代码示例: 先修改线程类 ```java public class DemoRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 20000; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); if (i % 10 == 0 && Thread.currentThread().getName().equals("线程1")) { System.out.println(Thread.currentThread().getName() + "让行"); Thread.yield(); } } } } ``` 主进程运行代码 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); Thread t2 = new Thread(new DemoRunnable()); t2.setName("线程2"); t1.start(); t2.start(); ``` 上述改动后每次线程1循环到10的倍数时会让线程2优先执行一段时间(不确定) ## 六、线程中断 #### 1、自动中断(线程运行完毕) 当线程中`run()`或`call()`执行完毕后会自动发生中断,表示线程已经结束且不能再次被启动。 #### 2、手动中断 **常用方法** | 方法 | 所属对象 | 作用 | | :----------------------------- | :------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `void interrupt()` | `Thread` 实例 | **中断目标线程**。设置目标线程的**中断状态标志**为 `true`。如果目标线程正被 `wait()`, `join()`, `sleep()` 阻塞,则会抛出 `InterruptedException`,并**清空中断状态(设置为 `false`)**。 | | `static boolean interrupted()` | `Thread` 类 | **检查当前线程是否被中断**,并**清空中断状态**。这是一个静态方法。如果连续调用两次,第二次很可能返回 `false`。 | | `boolean isInterrupted()` | `Thread` 实例 | **检查目标线程的中断状态**,**不清除**中断状态。 | ##### 场景一:线程在运行中(未被阻塞) 当线程正在执行时,中断只是设置了一个标志位,不会立即停止线程。线程需要自己定期检查这个标志位,并决定如何做。 ```java public class RunningInterruptionDemo { public static void main(String[] args) throws InterruptedException { Thread taskThread = new Thread(new LongRunningTask()); taskThread.start(); // 主线程运行3秒后,中断任务线程 Thread.sleep(3000); System.out.println("主线程发送中断请求..."); taskThread.interrupt(); // 设置中断标志位 } static class LongRunningTask implements Runnable { @Override public void run() { // 方法1:定期检查中断状态 while (!Thread.currentThread().isInterrupted()) { // 模拟一些工作单元 System.out.println("任务正在执行..."); try { // 模拟一个短时间工作,避免长时间工作导致无法及时响应中断 Thread.sleep(500); // 注意:这里sleep会被中断异常捕获! } catch (InterruptedException e) { // 在sleep期间被中断,会进入catch块,并且中断状态会被清除! System.out.println("在休眠时被中断,中断状态已重置为: " + Thread.currentThread().isInterrupted()); // 重要:通常在此处再次设置中断状态,因为业务逻辑可能需要知道发生了中断 Thread.currentThread().interrupt(); // 然后可以选择退出循环 break; } } // 方法2:或者在做耗时计算前检查 // for (int i = 0; i < 1_000_000 && !Thread.currentThread().isInterrupted(); i++) { // // 重型计算 // } System.out.println("任务线程已安全退出。"); } } } ``` ##### 场景二:线程在阻塞中(`wait`, `join`, `sleep`) 当线程在这些可中断的阻塞方法上时,如果收到中断信号,JVM 会立即让线程退出阻塞状态,并抛出 `InterruptedException`。 ```java public class BlockingInterruptionDemo { public static void main(String[] args) throws InterruptedException { Thread sleeperThread = new Thread(new SleeperTask()); sleeperThread.start(); // 让sleeperThread进入sleep状态 Thread.sleep(100); System.out.println("准备中断正在睡眠的线程..."); sleeperThread.interrupt(); // 此调用会触发sleep()方法抛出InterruptedException } static class SleeperTask implements Runnable { @Override public void run() { try { System.out.println("线程将要睡眠10秒..."); Thread.sleep(10000); // 这是一个可中断的阻塞方法 System.out.println("睡眠自然结束,这行应该不会被执行。"); } catch (InterruptedException e) { // 当sleep被interrupt()时,会跳转到这里 System.out.println("哎呀,睡眠被打断了!捕获到InterruptedException。"); System.out.println("此时线程的中断状态是: " + Thread.currentThread().isInterrupted()); // 输出: false // 恢复中断状态是一种良好实践,以便调用者能知道发生了中断 Thread.currentThread().interrupt(); } System.out.println("线程从阻塞状态恢复后继续执行。"); } } } ``` #### 3、为什么使用中断而不是 `stop()`? 历史上,Java 提供过 `stop()` 方法来强制终止线程,但它是**极其危险**的,已被废弃。原因如下: * **数据不一致**:`stop()` 会立即释放线程持有的所有锁,可能使对象处于不一致的状态。 * **资源泄漏**:它可能使一些资源(如文件句柄、网络连接)无法被正确关闭。 #### 4、响应中断的模板代码 对于需要长时间运行的任务,使用以下模板: ```java public void run() { try { while (!Thread.currentThread().isInterrupted()) { // 执行一个工作单元 doWorkUnit(); } } catch (InterruptedException e) { // 当doWorkUnit()中可能抛出InterruptedException时,在此捕获 Thread.currentThread().interrupt(); // 重新设置中断状态 } finally { // 在这里进行资源清理工作,确保一定会执行 cleanup(); } } private void doWorkUnit() throws InterruptedException { // 如果你的操作是可中断的,就直接抛出InterruptedException // 例如:Socket操作、BlockingQueue操作等 // 或者使用 Thread.sleep() } ``` Loading... ## 一、线程名称 #### 1、设置名称 setName() 设置的时候需要在线程实例化后和线程启动前进行命名。 ``` Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.start(); ``` #### 2、获取名称 getName() 若在线程外获取名称则直接调用`线程对象.getName()`即可 若在线程内获取名称则需要用到`Thread.currentThread().getName()`进行获取 ```java public class DemoRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 20000; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); } } } ``` ## 二、线程是否存活 使用方法`.isAlive()`,若存活则返回true。 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.start(); System.out.printf("%s是否存活:%s\n", t1.getName(), t1.isAlive());// 线程是否存活 try { Thread.sleep(2000); System.out.printf("%s是否存活:%s\n", t1.getName(), t1.isAlive());// 线程是否存活 } catch (InterruptedException e) { System.out.println(e.getMessage()); } ``` ## 三、线程优先级 #### 1、设置优先级 setPriority() 使用方法`.setPriority()`设置1~10的优先级,优先级越高线程越先运行 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.setPriority(1);// 设置1~10的优先级 Thread t2 = new Thread(new DemoRunnable()); t2.setName("线程2"); t2.setPriority(10);// 设置1~10的优先级 t1.start(); t2.start(); ``` 运行时虽然线程1比线程2先执行,但输出结果为线程2先输出 #### 2、获取优先级 getPriority() 返回`int`类型的1~10优先级。 ## 四、合并线程 `join()`的作用是**等待目标线程执行终止**,即将两个交替运行的线程合并成一个顺序运行的线程。 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); t1.setPriority(1);// 设置1~10的优先级 Thread t2 = new Thread(new DemoRunnable()); t2.setName("线程2"); t2.setPriority(10);// 设置1~10的优先级 t1.start(); try { t1.join(); } catch (InterruptedException e) { System.out.println(e.getMessage()); } t2.start(); System.out.printf("%s是否存活:%s\n", t1.getName(), t1.isAlive());// 线程是否存活 ``` 上述代码中虽然线程1的优先级远低于线程2,但因在两个线程之间执行了`t1.join()`,将t1线程与主线程合并,所以主线程等待t1线程运行结束后才会执行`t2.start()`。 ## 五、线程让行 `yield()`方法**提示调度器**当前线程愿意让出CPU,仅对优先级相同的线程有效。 代码示例: 先修改线程类 ```java public class DemoRunnable implements Runnable { @Override public void run() { for (int i = 0; i < 20000; i++) { System.out.println(Thread.currentThread().getName() + ":" + i); if (i % 10 == 0 && Thread.currentThread().getName().equals("线程1")) { System.out.println(Thread.currentThread().getName() + "让行"); Thread.yield(); } } } } ``` 主进程运行代码 ```java Thread t1 = new Thread(new DemoRunnable()); // 名称在线程实例化、执行之前进行设置 t1.setName("线程1"); Thread t2 = new Thread(new DemoRunnable()); t2.setName("线程2"); t1.start(); t2.start(); ``` 上述改动后每次线程1循环到10的倍数时会让线程2优先执行一段时间(不确定) ## 六、线程中断 #### 1、自动中断(线程运行完毕) 当线程中`run()`或`call()`执行完毕后会自动发生中断,表示线程已经结束且不能再次被启动。 #### 2、手动中断 **常用方法** | 方法 | 所属对象 | 作用 | | :----------------------------- | :------------ | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `void interrupt()` | `Thread` 实例 | **中断目标线程**。设置目标线程的**中断状态标志**为 `true`。如果目标线程正被 `wait()`, `join()`, `sleep()` 阻塞,则会抛出 `InterruptedException`,并**清空中断状态(设置为 `false`)**。 | | `static boolean interrupted()` | `Thread` 类 | **检查当前线程是否被中断**,并**清空中断状态**。这是一个静态方法。如果连续调用两次,第二次很可能返回 `false`。 | | `boolean isInterrupted()` | `Thread` 实例 | **检查目标线程的中断状态**,**不清除**中断状态。 | ##### 场景一:线程在运行中(未被阻塞) 当线程正在执行时,中断只是设置了一个标志位,不会立即停止线程。线程需要自己定期检查这个标志位,并决定如何做。 ```java public class RunningInterruptionDemo { public static void main(String[] args) throws InterruptedException { Thread taskThread = new Thread(new LongRunningTask()); taskThread.start(); // 主线程运行3秒后,中断任务线程 Thread.sleep(3000); System.out.println("主线程发送中断请求..."); taskThread.interrupt(); // 设置中断标志位 } static class LongRunningTask implements Runnable { @Override public void run() { // 方法1:定期检查中断状态 while (!Thread.currentThread().isInterrupted()) { // 模拟一些工作单元 System.out.println("任务正在执行..."); try { // 模拟一个短时间工作,避免长时间工作导致无法及时响应中断 Thread.sleep(500); // 注意:这里sleep会被中断异常捕获! } catch (InterruptedException e) { // 在sleep期间被中断,会进入catch块,并且中断状态会被清除! System.out.println("在休眠时被中断,中断状态已重置为: " + Thread.currentThread().isInterrupted()); // 重要:通常在此处再次设置中断状态,因为业务逻辑可能需要知道发生了中断 Thread.currentThread().interrupt(); // 然后可以选择退出循环 break; } } // 方法2:或者在做耗时计算前检查 // for (int i = 0; i < 1_000_000 && !Thread.currentThread().isInterrupted(); i++) { // // 重型计算 // } System.out.println("任务线程已安全退出。"); } } } ``` ##### 场景二:线程在阻塞中(`wait`, `join`, `sleep`) 当线程在这些可中断的阻塞方法上时,如果收到中断信号,JVM 会立即让线程退出阻塞状态,并抛出 `InterruptedException`。 ```java public class BlockingInterruptionDemo { public static void main(String[] args) throws InterruptedException { Thread sleeperThread = new Thread(new SleeperTask()); sleeperThread.start(); // 让sleeperThread进入sleep状态 Thread.sleep(100); System.out.println("准备中断正在睡眠的线程..."); sleeperThread.interrupt(); // 此调用会触发sleep()方法抛出InterruptedException } static class SleeperTask implements Runnable { @Override public void run() { try { System.out.println("线程将要睡眠10秒..."); Thread.sleep(10000); // 这是一个可中断的阻塞方法 System.out.println("睡眠自然结束,这行应该不会被执行。"); } catch (InterruptedException e) { // 当sleep被interrupt()时,会跳转到这里 System.out.println("哎呀,睡眠被打断了!捕获到InterruptedException。"); System.out.println("此时线程的中断状态是: " + Thread.currentThread().isInterrupted()); // 输出: false // 恢复中断状态是一种良好实践,以便调用者能知道发生了中断 Thread.currentThread().interrupt(); } System.out.println("线程从阻塞状态恢复后继续执行。"); } } } ``` #### 3、为什么使用中断而不是 `stop()`? 历史上,Java 提供过 `stop()` 方法来强制终止线程,但它是**极其危险**的,已被废弃。原因如下: * **数据不一致**:`stop()` 会立即释放线程持有的所有锁,可能使对象处于不一致的状态。 * **资源泄漏**:它可能使一些资源(如文件句柄、网络连接)无法被正确关闭。 #### 4、响应中断的模板代码 对于需要长时间运行的任务,使用以下模板: ```java public void run() { try { while (!Thread.currentThread().isInterrupted()) { // 执行一个工作单元 doWorkUnit(); } } catch (InterruptedException e) { // 当doWorkUnit()中可能抛出InterruptedException时,在此捕获 Thread.currentThread().interrupt(); // 重新设置中断状态 } finally { // 在这里进行资源清理工作,确保一定会执行 cleanup(); } } private void doWorkUnit() throws InterruptedException { // 如果你的操作是可中断的,就直接抛出InterruptedException // 例如:Socket操作、BlockingQueue操作等 // 或者使用 Thread.sleep() } ``` 最后修改:2025 年 10 月 13 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 👆请简单粗暴地爱我。