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

news2025/7/18 5:53:05

线程实例化

继承 Thread 类

  1. 创建类继承自 Thread 类 .

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

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

实现 Runnable 接口

  1. 创建类实现 Runnable 接口 .

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

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

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

实现 Callable 和 Future 接口 ( FutureTask )

run() 方法没有返回值 .

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

    class MyCallable implements Callable<V>{
        @Override
        public 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.coloradmin.cn/o/2373838.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

卫宁健康WiNGPT3.0与WiNEX Copilot 2.2:医疗AI创新的双轮驱动分析

引言:医疗AI的双翼时代 在医疗信息化的浪潮中,人工智能技术的深度融入正在重塑整个医疗行业。卫宁健康作为国内医疗健康和卫生领域数字化解决方案的领军企业,持续探索AI技术在医疗场景中的创新应用。2025年5月10日,在第29届中国医院信息网络大会(CHIMA2025)上,卫宁健康…

I2C通讯

3.1. 本章节的代码仓库 1 2 3 4 5 6 #如之前有获取则可跳过 #获取仓库 git clone https://gitee.com/LubanCat/lubancat_rk_code_storage.git#代码所在的位置 lubancat_rk_code_storage/quick_start/i2c3.2. i2c I2C(Inter&#xff0d;Integrated Circuit)是一种通用的总线协…

Excel实现单元格内容拼接

一、应用场景&#xff1a; 场景A&#xff1a;将多个单元格拼接&#xff0c;比如写测试用例时&#xff0c;将多个模块拼接&#xff0c;中间用“-”隔开 场景B&#xff1a;将某单元格内容插入另一单元格固定位置&#xff08;例如在B1中添加A1的内容&#xff09; 二、实际应用&a…

2025前端面试遇到的问题(vue+uniapp+js+css)

Vue相关面试题 vue2和vue3的区别 一、核心架构差异 特性Vue2Vue3响应式系统基于Object.defineProperty基于Proxy&#xff08;支持动态新增/删除属性&#xff09;代码组织方式Options API&#xff08;data/methods分块&#xff09;Composition API&#xff08;逻辑按功能聚合&am…

广东省省考备考(第八天5.11)—言语:逻辑填空(每日一练)

错题 解析 第一空&#xff0c;搭配“期盼”&#xff0c;且根据“生命&#xff0c;是来自上天的馈赠”&#xff0c;可知父母对孩子的出生是非常期盼的。A项“望穿秋水”&#xff0c;形容对远地亲友的殷切盼望&#xff0c;C项“望眼欲穿”&#xff0c;形容盼望殷切&#xff0c;均…

github+ Picgo+typora

github Picgotypora 本文将介绍如何使用Picgo在typora中实现上传服务 创建github仓库以及配置token 创建仓库 注意需要Initialize 添加README 配置为public 配置token github点击头像找到setting 选择Developer setting 配置token generate 选第一个第二个都行(我这里选第…

[网安工具] IP 信息收集工具 —— LBD · 使用手册

&#x1f31f;想了解其它网安工具&#xff1f;看看这个&#xff1a;[网安工具] 网络安全工具管理 —— 工具仓库 管理手册 lbd | Kali Linux ToolsVideolbd Usage ExampleTest to see if the target domain (example.com) is using a load balancer:rootkali:~# lbd example.c…

说说es配置项的动态静态之分和集群配置更新API

这天因为某件工作来到了es官网某个参数配置相关的页面&#xff0c;注意到了下图圆圈里的“Dynamic”&#xff1a; 链接&#xff1a;https://www.elastic.co/guide/en/elasticsearch/reference/8.1/modules-cluster.html#misc-cluster-settings 显然这是对配置项的一个描述&am…

LLMs之Mistral Medium 3:Mistral Medium 3的简介、安装和使用方法、案例应用之详细攻略

LLMs之Mistral Medium 3&#xff1a;Mistral Medium 3的简介、安装和使用方法、案例应用之详细攻略 目录 Mistral Medium 3 简介 1、Mistral Medium 3 特点 Mistral Medium 3 安装和使用方法 2、使用方法 (1)、创建Agent (2)、模型微调 Mistral Medium 3 案例应用 Mistr…

并发设计模式实战系列(17):信号量(Semaphore)

&#x1f31f; 大家好&#xff0c;我是摘星&#xff01; &#x1f31f; 今天为大家带来的是并发设计模式实战系列&#xff0c;第十七章信号量&#xff08;Semaphore&#xff09;&#xff0c;废话不多说直接开始~ 目录 一、核心原理深度拆解 1. 信号量本质模型 2. 并发控制…

RAGMCP基本原理说明和相关问题解惑

一、RAG架构原理和局限性 1.1 概念解释 RAG&#xff08;Retrieval-Augmented Generation&#xff09;&#xff1a;检索增强生成&#xff0c;让大模型接受外部输入后&#xff0c;总结输出 向量数据库&#xff1a;向量数据通常是高维空间中的点&#xff0c;代表复杂的数据结构…

Java学习手册:服务注册与发现

一、服务注册与发现的概念 在微服务架构中&#xff0c;服务注册与发现是核心功能之一。由于微服务架构中服务实例的数量和位置是动态变化的&#xff0c;服务注册与发现机制允许服务实例在启动时自动注册到注册中心&#xff0c;并在停止时自动注销。其他服务可以通过查询注册中…

双向Transformer:BERT(Bidirectional Encoder Representations from Transformers)

基于Transformer架构&#xff0c;通过双向上下文建模训练&#xff0c;提高完成任务的性能。 一 BERT的核心理念 1.1双向上下文建模依赖 之前讲的双向递归是用两个RNN进行&#xff0c;而BERT是通过Transformer的自注意力机制同时捕捉上下文信息。 1.1.1掩码语言模型&#xf…

EdgeOne Pages MCP 入门教程

什么是MCP&#xff1f; MCP (Model Context Protocol) 是一个开放协议&#xff0c;允许 AI 模型安全地与本地和远程资源进行交互。通过在支持 MCP 的客户端&#xff08;如 Cline、Cursor、Claude 等&#xff09;上进行统一配置&#xff0c;可以让 AI 访问更多资源并使用更多工…

Maven 公司内部私服中央仓库搭建 局域网仓库 资源共享 依赖包构建共享

介绍 公司内部私服搭建通常是为了更好地管理公司内部的依赖包和构建过程&#xff0c;避免直接使用外部 Maven 中央仓库。通过搭建私服&#xff0c;团队能够控制依赖的版本、提高构建速度并增强安全性。公司开发的一些公共工具库更换的提供给内部使用。 私服是一种特殊的远程仓…

1688代采系统:技术架构与应用实践

在电商领域&#xff0c;1688 作为国内领先的 B2B 电商平台&#xff0c;拥有海量的商品信息。这些数据对于企业采购决策、市场分析、价格监控和供应链管理具有重要价值。本文将详细介绍如何使用 Python 爬虫技术&#xff0c;通过 1688 的商品详情接口&#xff08;item_search 和…

一种混沌驱动的后门攻击检测指标

摘要 人工智能&#xff08;AI&#xff09;模型在各个领域的进步和应用已经改变了我们与技术互动的方式。然而&#xff0c;必须认识到&#xff0c;虽然人工智能模型带来了显著的进步&#xff0c;但它们也存在固有的挑战&#xff0c;例如容易受到对抗性攻击。目前的工作提出了一…

【2025最新】为什么用ElasticSearch?和传统数据库MySQL与什么区别?

Elasticsearch 深度解析&#xff1a;从原理到实践 一、为什么选择 Elasticsearch&#xff1f; 数据模型 Elasticsearch 是基于文档的搜索引擎&#xff0c;它使用 JSON 文档来存储数据。在 Elasticsearch 中&#xff0c;相关的数据通常存储在同一个文档中&#xff0c;而不是分散…

c++的模板和泛型编程

c的模板和泛型编程 泛型编程函数模板函数模板和模板函数函数模板的原理函数模板的隐式、显式实例化模板参数的匹配原则 类模板类模板的实例化模板的使用案例用函数模板运行不同的模板类用函数模板运行不同的STL容器 模板的缺省参数非类型模板参数模板的特化函数模板的特化类模板…

Java从入门到精通 - 数组

数组 此笔记参考黑马教程&#xff0c;仅学习使用&#xff0c;如有侵权&#xff0c;联系必删 文章目录 数组1. 认识数组2. 数组的定义和访问2.1 静态初始化数组2.1.1 数组的访问2.1.1 定义代码实现总结 2.1.2 数组的遍历2.1.2.1 定义代码演示总结 案例代码实现 2.2 动态初始化…