当前位置: 首页 > news >正文

【Java】线程实例化 线程状态 线程属性

线程实例化

继承 Thread 类

  1. 创建类继承自 Thread 类 .

    class MyThread extends Thread
    
  2. 重写 run() 方法 .

    	@Overridepublic void run(){// 线程要执行的任务代码}
    
  3. 实例化自定义线程类 .

实现 Runnable 接口

  1. 创建类实现 Runnable 接口 .

    class MyRunnable implements Runnable
    
  2. 实现 run() 方法 .

    	@Overridepublic void run() {// 线程要执行的任务代码}
    
  3. 实例化传递实现类对象作为 Thread 构造函数的参数的对象 .

    Thread thread = new Thread(new MyRunnable());
    

实现 Callable 和 Future 接口 ( FutureTask )

run() 方法没有返回值 .

  1. 创建类实现 Callable 接口 , 实现有返回值的 call() 方法 .

    class MyCallable implements Callable<V>{@Overridepublic V call() {// 线程要执行的任务代码}
    }
    
  2. 创建管理多线程运行结果的 Future 接口的实现类 FutureTask 的对象 , 构造方法传递实现类 MyCallable 的对象 .

    FutureTask<V> ft = new FutureTask<>(new MyCallable());
    
  3. 创建 Thread 对象 , 构造方法传递 FutureTask 实现类的对象 .

方法

get

FutureTask 提供了两种重载 get 方法用于获取线程运行结果 :

  • V get():此方法会让当前线程阻塞 , 直到线程返回结果或在执行过程中抛出异常 .
  • V get(long timeout, TimeUnit unit):该方法同样会使当前线程阻塞 , 不过会有超时限制 . 若在指定时间内任务未完成 , 就会抛出 TimeoutException 异常 .

cancel

  • 核心逻辑 :
    FutureTask 的 cancel 方法会尝试对线程调用 interrupt 方法中断线程 , 所以 cancel 方法只是请求取消 , 如果线程执行任务本身没有处理中断的代码逻辑 , 那么即使调用 cancel 方法 , 线程也会正常运行 .
  • 参数 :
    cancel 方法存在布氏值参数 mayInterruptIfRunning , 如果传入 true , 即表示当前线程处于 RUNNABLE 状态 , cancel 方法会尝试调用 interrupt 方法 , 如果传入 false , 只有在线程运行前 ( NEW 状态 ) 才能取消任务 .
  • 返回值 :
    cancel 方法的返回值是是否请求取消成功的布尔值 , 即使线程执行任务没有处理中断的逻辑也会返回 true .
  • 旁支方法 :
    isCanceled 方法顾名思义 , 不论线程是否结束运行 , 只要 FutureTask 对象成功调用了 cancel 方法 , 该方法就会返回 true .
    isDone 方法返回线程任务是否完成 , 任务完成状态有三 : 正常结束运行 , 抛出异常终止 和 调用 cancel 方法取消 .

线程状态

Thread.State 枚举类定义

  1. NEW 新建状态
    通过 new 关键字实例化 Thread 对象后 , 未调用 start() 方法前 .

  2. RUNNABLE 可运行状态
    调用 start() 方法后 , 线程处于可运行状态 .

    1. Ready 就绪状态 : 线程获得除 CPU 时间片之外所有的必要资源后 , 获得 CPU 时间片之前 .
    2. Running 运行状态 : 获得 CPU 时间片后 , 执行 run() 代码时 .

    CPU 时间片 也称为 调度量子 , 是操作系统用于管理多任务处理的一个概念 . 在多任务操作系统中 , 多个程序看似同时运行,但实际上一个CPU在同一时刻只能执行一个任务 . 为了实现多任务处理的假象 , 操作系统会将CPU的执行时间分割成一系列的小时间段,每个时间段就被称为 时间片 .

    操作系统内核中的调度器会给每个正在运行的任务分配一个时间片 , 任务在这个时间片内获得 CPU 的使用权来执行 . 一旦当前任务的时间片用完 , 无论该任务是否已完成 , 调度器都会暂停当前任务 , 切换到等待任务 , 并给当前任务分配新的时间片来执行 . 通过快速地在不同任务之间切换 , 操作系统创造出多个程序同时运行的效果 .

  3. BLOCKED 阻塞状态
    线程尝试获取被其他线程占用的锁后 , 获得锁前 .

  4. WAITING 等待状态
    线程调用 Object.wait() , Thread.join()LockSupport.park() 方法后会进入等待状态 . 处于等待状态的线程会无限期地等待 , 直到其他线程调用相应的唤醒方法 .

  5. TIMED_WAITING 定时等待状态
    与等待状态类似 , 但定时等待状态的线程会在指定的时间后自动唤醒 .

  6. TERMINATED 终止状态
    线程的 run() 方法执行完毕 或 因异常意外结束后 . 终止状态的线程已经结束了生命周期 , 不能重新启动 .

    再次调用 start() 方法会抛出 IllegalThreadStateException 异常 , 想达到类似重新启动的效果要重新实例化一个实现类相同的线程 .

在这里插入图片描述

线程属性

线程中断

线程中断是线程间通信 ( 控制线程的运行状态 ) 的早期手段 .

中断标志位

布尔类型 , 用于表示线程是否被请求中断 . 查询方法有两种 :

  1. public boolean isInterrupted() 查询调用线程的中断状态 , 不清除中断标志位 : 即重置中断标志位为 false .
  2. public static boolean interrupted() 查询调用线程的中断状态 , 清除中断标志位 .

InterruptException

编译时异常 , 阻塞线程 ( 状态有 BLOCKED , WAITING , TIME_WAITING ) 被其他线程中断时抛出 , 因为如果不抛出异常 , 线程无法回到原本的运行状态 . 抛出异常后 , 中断标志位被清除 .

RUNNABLE 线程调用 interrupt() 会怎么样 ?

中断无效 , 线程中断方法只能设置线程的中断标志位为 true , 表示线程被请求中断 , 线程会继续执行代码直到主动检出中断标志位 .

作用

Java 的线程中断是协作式中断 , 不会直接停止线程 , 而是提供中断标志查询 , 后续怎么处理会交给线程自己 . 处于等待或者阻塞状态的线程被中断 , 只有抛出 ie 异常后才能转换成 RUNNABLE 状态继续执行后续逻辑 . 对于 RUNNABLE 状态只是打了个标记 , 后续怎么执行看是否要对中断标记进行处理 .

  1. 安全退出线程 , 在希望结束线程任务前自主控制资源释放 .
  2. 取消线程的阻塞状态 , 提供线程间通信的一种手段 .
    如调整线程 2 为响应阻塞状态或睡眠足够长时间 , 在线程 1 执行完代码或到达关键代码后中断线程 2 , 强制线程 2 从睡眠中醒来 , 执行异常抛出代码后恢复 RUNNABLE 可运行状态 , 开始执行代码 .

线程守护

setDaemon(boolean on) 设置调用线程为守护状态 , 当所有的非守护线程结束时 , JVM 会自动退出 , 即使守护线程仍在运行 . 可以通过 isDaemon() 查询守护状态 , 新创建的线程默认是非守护线程 false .

Tips

  1. 必须在 start() 方法调用前设置守护状态 .
  2. 守护线程的 finally 块可能不会执行 .

守护线程可以用来执行非关键的后台任务 , 如 JVM 垃圾回收 等 .

线程名

线程名与线程变量名是两个完全不同的概念 , 前者是线程的属性 , 可以存在于日志等记录中 ; 后者仅存在于源代码中 , 编译后没有实际意义 , 与线程本身无关 .

线程名可以通过 setName() 方法或在带参构造中传递 , 如果一个线程由无参构造实例化 , 其名称会按照 "Thread-" + n 的格式自动生成 , 其中 n 是由 JVM 内部维护的线程计数器决定的递增数字 :

private static synchronized int nextThreadNum() {return threadInitNumber++;
}
this.name = "Thread-" + nextThreadNum();

未捕获异常处理器

public interface Runnable {void run();
} // Runnable 接口的 run() 不能声明抛出任何受检异常.

throws 抛出异常是向上抛出 , 交给方法调用者来处理 ; catch 捕获是自行处理 , run() 作为通用任务接口 , 无法确定所有可能的异常类型 , 若允许抛出受检异常 , 多方调用者会被强制处理所有异常 , 导致代码冗余 .

线程异常通过 catch 捕获和未捕获异常处理器协作完成 . 未捕获异常处理器有 全局处理器 , 特定处理器 , 组处理器三种 , 通过 setDefaultUncaughtExceptionHandler() 方法设置 .

线程中的异常未被捕获时 , 线程的 UncaughtExceptionHandler 会被触发执行 , JVM 会调用该线程所设置的 UncaughtExceptionHandler 中的 uncaughtException 方法 , 并将抛出异常的线程对象和异常实例作为参数传递给该方法 , 从而执行在方法里所定义的异常处理逻辑 . 执行完处理器的处理代码后 , 线程会终止 .

如果线程组或全局的处理器管理的一个线程出现了未捕获异常 , 其他线程不会因为异常被连带终止 . 异常只会影响出现未捕获异常的线程 , 不会波及其他线程 .

当线程抛出一个未捕获异常时 , JVM 会按照 特定处理器 - 组处理器 - 全局处理器 的顺序查找 , 如果查找均失败则打印堆栈追踪并终止线程 .

Tips

  1. 处理器中抛出的异常不会传播到更外层 .

    Thread.setUncaughtExceptionHandler((t, e) -> {System.out.println("处理原始异常: " + e.getMessage());throw new RuntimeException("处理器中的新异常"); // 这个异常会被忽略
    });
    
  2. 对于线程池 , 要为每个任务单独处理异常 .

线程优先级

线程优先级用于表示线程执行的相对重要程度 , JVM 和 操作系统会依据线程的优先级安排线程调度 .

设置和范围

setPriority() 方法设置线程优先级 , getPriority() 方法获取线程的当前优先级 .

线程优先级取值范围是 1 到 10 , Thread.MIN_PRIORITY = 1 最低优先级 , Thread.NORM_PRIORITY = 5 默认优先级 , Thread.MAX_PRIORITY = 10 最高优先级 .

缺陷

线程调度主要由操作系统负责 , 线程优先级依赖于操作系统 , 优先级值会映射到宿主机平台优先级 , 操作系统可能会根据线程的行为动态调整优先级 . 所以一般不用 , 了解即可 .

Thread.MIN_PRIORITY = 1 最低优先级 , Thread.NORM_PRIORITY = 5 默认优先级 , Thread.MAX_PRIORITY = 10 最高优先级 .

缺陷

线程调度主要由操作系统负责 , 线程优先级依赖于操作系统 , 优先级值会映射到宿主机平台优先级 , 操作系统可能会根据线程的行为动态调整优先级 . 所以一般不用 , 了解即可 .

http://www.xdnf.cn/news/391681.html

相关文章:

  • AUTOSAR图解==>AUTOSAR_TR_HWTestManagementIntegrationGuide
  • REST/SOAP 协议介绍及开发示例
  • web animation API 锋利的css动画控制器 (更新中)
  • Python高级爬虫之JS逆向+安卓逆向2.1节: 网络爬虫核心原理
  • 【c++】【数据结构】二叉搜索树详解
  • InnoDB引擎
  • JVM规范之运行时数据区域
  • 【沉浸式求职学习day36】【初识Maven】
  • 低功耗蓝牙BLE之发射功率(mW/dBm)对应关系
  • jna总结1
  • 26考研——中央处理器_指令流水线_指令流水线的基本概念 流水线的基本实现(5)
  • 在C++中,符号位是否参与位运算
  • BUUCTF——Ezpop
  • [Java实战]Spring Boot 静态资源配置(十三)
  • Appium-OppoA92S-真机记坑
  • ARP协议的工作原理
  • Linux `uname` 指令终极指南
  • 无需大规模重训练!GraspCorrect:VLM赋能机器人抓取校正,抓取成功率提升18.3%
  • 如何使用 Netstat 查看监听端口
  • 环形链表(简单)
  • 谈程序的地址空间
  • 智能座舱开发工程师面试题
  • 代码随想录算法训练营第六十天| 图论7—卡码网53. 寻宝
  • 《AI大模型应知应会100篇》第55篇:大模型本地开发环境搭建
  • 机器人运动控制原理浅析-UC Berkeley超视觉模态模型
  • LangGraph框架中针对MCP协议的变更-20250510
  • android-ndk开发(12): 获取ndk内置clang的版本详情
  • git 报错:错误:RPC 失败。curl 28 Failed to connect to github.com port 443 after 75000
  • YashanDB(崖山数据库)V23.4 LTS 正式发布
  • 用户态到内核态:Linux信号传递的九重门(一)