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

Java线程 - 详解(1)

一,创建线程

方法一:继承Thread类

class MyThread extends Thread{@Overridepublic void run() {System.out.println("线程1");}
}public class Test {public static void main(String[] args) {MyThread myThread = new MyThread();myThread.start();//start()方法启动线程//和上面的方法一样,只不过使用匿名内部类实现Thread thread1 = new Thread(){@Overridepublic void run() {System.out.println("线程2");}};thread1.start();}
}

方法二:实现Runnable接口

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("线程1");}
}
public class Test {public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();//匿名内部类实现Thread thread2 = new Thread(new Runnable() {@Overridepublic void run() {System.out.println("线程2");}});thread2.start();//lambda表达式实现Thread thread3 = new Thread(() -> System.out.println("线程3"));thread3.start();}
}

二,Thread类及常见方法

2.1 构造方法

方法说明
Thread()创建线程对象
Thread(Runnable  target)使用Runnable对象创建线程对象
Thread(String  name)创建线程对象并命名
Thread(Runnable  target,String  name)使用Runnable对象创建线程对象,并命名
Thread(ThreadGroup  group,Runnable  target)线程可以被用来分组管理,分好的组即为线程组(了解即可)

2.2 获取 Thread 的常见属性

属性获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()
  • ID是线程的唯一标识,ID是JAVA分配的,不会出现重复的,与上篇博客中PCB结构中的pid不是同一个东西。
  • 名称是方便各种调试工具使用。
  • 后台线程不会影响线程的结束,前台线程会影响线程的结束,一般线程默认为前台线程,还有一个注意点——JVM会在一个进程的所有后台进程结束后,才会结束运行。
  • 是否存活,简单理解就是 run 方法是否运行结束。
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{System.out.println("线程开始");try {Thread.sleep(1000);//休眠线程 xxx ms} catch (InterruptedException e) {throw new RuntimeException(e);}},"1号线程");thread.setDaemon(true);//设置为后台线程thread.start();System.out.println(thread.getName() + " " + thread.isAlive());Thread.sleep(3000);System.out.println("线程结束");System.out.println(thread.isAlive());}
}

 

2.3 start()  与  run() 的区别

作用功能:

  1. start()方法内部是会调用系统的API,在系统内核创建一个线程
  2. run()方法只是描述线程具体实现的任务(会在start创建好之后会自动被调用)

运行结果:

  1. start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
  2. run方法是一个类中的普通方法,主动调用和调用普通方法一样,会顺序执行一次

 2.4 中断一个线程

在Java中,终止/销毁一个线程的做法比较单一,就是尽快让 run 方法执行结束。

方法一: 在代码中手动创建一个标志位,来作为 run 的执行结束条件,比如在很多线程中,执行时间长往往是写了一个循环。

public class Demo {private static boolean isQuit = false;//通过类属性来控制public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while (!isQuit){System.out.println("666");}});thread.start();Thread.sleep(1);isQuit = true;}
}

 注:这里的 isQuit 不能是局部变量,因为如果是局部变量就不满足 lambda表达式中的变量捕获语法。

但是上面的方法有两个缺点:1. 需要手动创建变量 2. 当线程内部在 sleep 的时候,主线程修改变量时,新线程内部不能及时响应,所以Java提供了另一种解决方法:

方法二:使用 interupt() 和 isInterrupted()

方法说明
public void interrupt()中断对象关联的线程,如果线程阻塞,则以异常方式通知,否则设置标志位
public static boolean interrupted()判断当前线程中的标志位是否设置,调用后清除标志位
public boolean isInterrupted()判断对象关联的线程的标志位是否设置,调用后不清除标志
public class Demo {public static void main(String[] args) {Thread thread = new Thread(()->{// Thread.currentThread()作用是得到当前的线程// isInterrupted() 判断标识符是否为false//或者 while(!Thread.interrupted()) 效果一样while(!Thread.currentThread().isInterrupted()){System.out.println("线程工作中!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//打印异常}}});thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();//将标识符设置为true}
}

但是报错后,该线程没有中断,而是继续执行,这是为什么呢?

这是因为当我们将 标识符设为true 时,正好线程在sleep,会触发sleep内部的一个异常,从而会将线程从sleep中唤醒,但是在sleep抛出异常的同时,它会自动删除刚才设置的 标志位,这将会使 interrupt 这一操作好像没有被执行。

为什么Java会这样设定呢? 因为 Java 是希望当 线程收到 "中断" 信号时,它能自由决定接下来要怎么处理,比如:我们可以在打印报错后 接着写一些代码 :

public class Demo {public static void main(String[] args) {Thread thread = new Thread(()->{// Thread.currentThread()作用是得到当前的线程// isInterrupted() 判断标识符是否为false//或者 while(!Thread.interrupted()) 效果一样while(!Thread.currentThread().isInterrupted()){System.out.println("线程工作中!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();//打印异常System.out.println("还需要完成的操作...");//2.break;//1.直接退出}}});thread.start();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}thread.interrupt();//将标识符设置为true}
}

 注:

  1. 如果没有sleep,就不会出现上述情况,线程会直接退出!!!
  2. 我们不建议使用 Thread.interrupted() 这种做法,因为该方法是静态方法,意味着所有的线程共用一个标识符,而我们使用的线程肯定不止一个,如果使用该方法,就乱套了!!!

2.5 等待一个线程 - join()

作用:让一个线程等待另一个线程执行结束后,在继续执行。本质上是控制线程结束的顺序。

方法作用
public void join()等待线程结束
public void join(long millis)等待线程结束,但是最多等待 millis 毫秒
public void join(long millis, int nanos)同上,但是精度更高
public class Demo1 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 5; i++) {System.out.println("线程工作中!");try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}});thread.start();System.out.println("main线程开始等待");thread.join();System.out.println("等待结束");}
}

 注:

  1. 要分清哪个线程是等待的,哪个线程是被等待的
  2. join() 会出现 "死等" 的情况,我们一般不会使用,建议使用有参数的,可以自定义等待时间

2.6 其他 

方法作用
public static Thread currentThread()返回当前线程对象的引用
public static void sleep(long millis) throws interruptedException当前线程休眠millis毫秒
public static void sleep(long millis, int nanos) throws interruptedException同上,精度更高

三,线程的状态

  •  NEW:  Thread 对象已经有了,start 方法还没有调用
  • TERMINATED:  Thread 对象还在,内核中的线程已经没了
  • RUNNABLE:  就绪状态 (线程已经在 CPU 上运行 / 线程正在排队等待去 CPU 上运行)
  • TIME_WAITING:  阻塞,由于 sleep 这种固定时间的方式产生阻塞
  • WAITING:  阻塞,由于 wait 这种不固定时间的方式产生阻塞
  • BLOCKED:  阻塞,由于锁竞争导致的阻塞
public class Demo2 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 5; i++) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}});// getState() 获得当前线程的状态System.out.println(thread.getState());thread.start();for (int i = 0; i < 3; i++) {System.out.println(thread.getState());Thread.sleep(200);}thread.join();System.out.println(thread.getState());}
}

 

 

相关文章:

Java线程 - 详解(1)

一&#xff0c;创建线程 方法一&#xff1a;继承Thread类 class MyThread extends Thread{Overridepublic void run() {System.out.println("线程1");} }public class Test {public static void main(String[] args) {MyThread myThread new MyThread();myThread.…...

结构体-C语言(初阶)

目录 一、结构体声明 1.1 结构概念 1.2 结构声明 1.3 结构成员的类型 1.4 结构体变量的定义和初始化 二、结构体成员的访问 2.1 结构体变量访问成员 2.2 结构体指针访问指向变量的成员 三、结构体传参 一、结构体声明 1.1 结构概念 结构是一些值的集合&#xff0c;这些值称为…...

【网络】HTTPS的加密

目录 第一组&#xff0c;非对称加密第二组&#xff0c;非对称加密第三组&#xff0c;对称加密证书签名 HTTPS使用的是非对称加密加对称加密的方案 &#xff08;非对称加密&#xff1a;公钥加/解密&#xff0c;私钥解/加密&#xff09; &#xff08;对称加密&#xff1a;一组对称…...

Nacos安装指南

Nacos安装指南 1.Windows安装 开发阶段采用单机安装即可。 1.1.下载安装包 在Nacos的GitHub页面&#xff0c;提供有下载链接&#xff0c;可以下载编译好的Nacos服务端或者源代码&#xff1a; GitHub主页&#xff1a;https://github.com/alibaba/nacos GitHub的Release下载…...

java-Optional 类详解

目录 前言 Optional的构造方法 Optional的相关方法介绍 isPresent用法&#xff1a; get用法&#xff1a; filter用法&#xff1a; orElse用法&#xff1a; orElseGet用法 orElseThrow用法 map用法 flatMap用法&#xff1a; 前言 Optional 类是java8的新特性&#xff0…...

sql数据库怎么备份,sql 实时备份

在当今互联网时代&#xff0c;数据已经成为企业的核心资产。然而&#xff0c;数据的安全性和完整性面临硬件问题、软件故障、人工操作错误等各种威胁。为了保证数据的安全&#xff0c;实时备份已经成为公司必须采取的重要措施之一。下面我们就重点介绍SQL实时备份的重要实施方法…...

RK3399平台开发系列讲解(存储篇)Linux 存储系统的 I/O 栈

平台内核版本安卓版本RK3399Linux4.4Android7.1🚀返回专栏总目录 文章目录 一、Linux 存储系统全景二、Linux 存储系统的缓存沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 Linux 存储系统的 I/O 原理。 一、Linux 存储系统全景 我们可以把 Linux 存储系…...

Java“牵手”天猫淘口令转换API接口数据,天猫API接口申请指南

天猫平台商品淘口令接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取天猫商品的标题、价格、库存、商品快递费用&#xff0c;宝贝ID&#xff0c;发货地&#xff0c;区域ID&#xff0c;快递费用&#xff0c;月销量、总销量、库存、详情描…...

postgresql 条件表达式

postgresql 条件表达式 简单CASE表达式搜索CASE表达式缩写函数nullif函数示例 coalesce函数 总结 简单CASE表达式 语法如下 case 表达式when 值1 then 结果1when 值2 then 结果2else 默认值 end;select e.first_name , e.last_name , case e.department_id when 90 then 管…...

姜启源数学模型第五版第五章火箭发射升空

姜启源数学模型第五版第五章例题内容复现 数学建模背景1.学习内容火箭发射升空理论知识 2.例题3.问题分析不考虑空气阻力的模型考虑空气阻力的模型 4.代码内容复现不考虑空气阻力考虑空气阻力模型 数学建模背景 首先先简单的介绍数学建模是一个怎么样的内容 数学建模是一种将数…...

局域网中电脑共享文件给手机

学习资源&#xff1a; 局域网共享&#xff1a;这样设置&#xff0c;你可以轻松拷贝任何电脑的文件。_哔哩哔哩_bilibili 可以实现什么效果&#xff1f; 连接同一个WIFI&#xff0c;电脑端为服务端&#xff0c;提供共享文件&#xff0c;手机是客户端&#xff0c;可以读取服务端…...

线段树练习

P1198 [JSOI2008] 最大数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) // Problem: P1198 [JSOI2008] 最大数 // Contest: Luogu // URL: https://www.luogu.com.cn/problem/P1198 // Memory Limit: 128 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://c…...

Mybatis映射.动态sql.分页

介绍&#xff1a; 动态SQL是MyBatis提供的一种动态生成SQL语句的方式&#xff0c;可以根据不同的条件生成不同的SQL语句&#xff0c;从而实现更加灵活的查询和操作。 在MyBatis的映射文件中&#xff0c;可以通过使用if、choose、when、otherwise、foreach等标签来实现动态SQL…...

springboot向resources下写文件的两种方式

文章目录 方式一&#xff1a;方式二&#xff1a; 方式一&#xff1a; import java.io.File; import java.io.FileWriter; import java.io.IOException;public class WriterFileUtils {private static final String prefix "classpath:";public static void writeFi…...

Sloare flare网卡信息

详细的安装信息 https://github.com/Xilinx-CNS/onload/tree/master/scripts 进行下载 Solarflare网卡开发&#xff1a;openonload 安装与调试_openonload安装_Erice_s的博客-CSDN博客 cns-sfnettest测试 cns-sfnettest 下载 https://github.com/Xilinx-CNS/cns-sfnettes…...

Redis知识点整理

第一部分&#xff1a;Redis基础知识点 1、数据类型 5种常用基础类型&#xff1a;string,hash,list,set,zset – 字符串&#xff0c;Hash表&#xff0c;List顺序集合&#xff0c;Set无序集合&#xff0c;ZSet有序集合3中特殊类型&#xff1a;bitmap-字节地图, hyperloglog-统计…...

React笔记(一)初识React

一、React概述 1、什么是react react的官网:React 用于构建用户界面的 JavaScript 库&#xff0c;它也是一个渐进式的用于构建用户界面的javascript框架 2、主要特征 声明式&#xff1a;使用原生JS编写的页面存在着开发效率低下、性能较差的情况&#xff0c;使用react大家就…...

C语言——指针进阶(一)

目录 ​编辑 一.字符指针 1.1 基本概念 1.2 面试题 二.指针数组 三.数组指针 3.1 数组指针的定义 3.2 &数组名VS数组名 3.3 数组指针的使用 四.数组参数、指针参数 4.1 一维数组传参 ​编辑 4.2 二维数组传参 4.3 一级指针传参 4.4 二级指针传参 ​编辑 五.…...

【ArcGIS Pro二次开发】(62):复制字段

应网友需求&#xff0c;做了这么一个复制字段的小工具。 假定这样一个场景&#xff0c;手头有一个要素1&#xff0c;要素里有10个字段&#xff0c;另一个要素2&#xff0c;除了shape_area等图形字段外&#xff0c;没有其它字段。 现在的需求是&#xff0c;想把要素1中的8个字…...

【Tkinter系列02/5】界面初步和布局

本文是系列文章第二部分。前文见&#xff1a;【Tkinter系列01/5】界面初步和布局_无水先生的博客-CSDN博客 说明 一般来说&#xff0c;界面开发中&#xff0c;如果不是大型的软件&#xff0c;就不必用QT之类的实现&#xff0c;用Tkinter已经足够&#xff0c;然而即便是Tkinter规…...

GLM-4-9B-Chat-1M惊艳效果:半导体IP核用户手册中时序约束自动提取与验证

GLM-4-9B-Chat-1M惊艳效果&#xff1a;半导体IP核用户手册中时序约束自动提取与验证 1. 引言&#xff1a;一个让芯片工程师头疼的日常 如果你是芯片设计工程师&#xff0c;或者从事数字电路验证工作&#xff0c;下面这个场景你一定不陌生。 项目进入关键阶段&#xff0c;你拿…...

lite-avatar形象库开源镜像优势:免依赖、免CUDA版本冲突、开箱即用

lite-avatar形象库开源镜像优势&#xff1a;免依赖、免CUDA版本冲突、开箱即用 1. 什么是lite-avatar形象库 lite-avatar形象库是一个基于HumanAIGC-Engineering/LiteAvatarGallery的数字人形象资产库&#xff0c;专门为开发者和研究者提供高质量的2D数字人形象资源。这个开源…...

ROS2导航实战:如何正确订阅rviz2的/goal_pose消息(附避坑指南)

ROS2导航实战&#xff1a;深度解析/goal_pose消息订阅与Rviz2插件机制 1. 引言&#xff1a;当导航目标消息"消失"时 在ROS2的Navigation2开发中&#xff0c;许多开发者都遇到过这样的困惑&#xff1a;明明在Rviz2中设置了"Navigation2 Goal"&#xff0c;但…...

SpringBoot策略模式实战:利用Map注入优雅管理多实现类

1. 为什么需要策略模式与Map注入 最近在重构一个图形处理系统时&#xff0c;我遇到了一个典型的多实现类问题。系统需要处理矩形、圆形、正方形等多种图形&#xff0c;每种图形都有自己的绘制逻辑。最初的做法是为每种图形创建单独的Service接口和实现类&#xff0c;结果代码迅…...

nRF52840-Dongle蓝牙抓包实战:从固件刷写到Wireshark配置全流程(附常见问题排查)

nRF52840-Dongle蓝牙抓包实战&#xff1a;从固件刷写到Wireshark配置全流程&#xff08;附常见问题排查&#xff09; 在物联网设备爆发式增长的今天&#xff0c;蓝牙低功耗&#xff08;BLE&#xff09;技术已经成为智能家居、可穿戴设备和工业传感器网络的核心连接方案。但对于…...

Vue项目实战:Element-UI树形下拉选择器封装全流程(附完整代码)

Vue项目实战&#xff1a;Element-UI树形下拉选择器深度封装指南 在复杂表单场景中&#xff0c;树形下拉选择器是平衡空间利用率和操作效率的经典解决方案。不同于常规平铺式选择器&#xff0c;它通过层级结构组织海量选项&#xff0c;特别适合部门选择、分类导航等具有父子关系…...

Visualized-BGE批量推理实战:如何用Python代码将图片编码速度提升3倍

Visualized-BGE批量推理实战&#xff1a;如何用Python代码将图片编码速度提升3倍 在当今多模态AI应用爆炸式增长的时代&#xff0c;高效处理图像嵌入已成为开发者面临的核心挑战之一。Visualized-BGE作为支持中英文的多模态嵌入模型&#xff0c;在跨模态检索任务中表现出色&…...

全年出货33万吨创纪录!尚太科技北苏二期投产背后的增长密码

全年出货33万吨创纪录&#xff01;尚太科技北苏二期投产背后的增长密码2025年&#xff0c;尚太科技以33万吨负极材料出货量刷新行业纪录&#xff0c;营收同比激增61.83%至33.88亿元&#xff0c;净利润达4.79亿元&#xff0c;同比增长34.37%&#xff0c;扣非净利润增速更高达40.…...

墨语灵犀爬虫数据智能处理:Python爬虫结果清洗与摘要生成

墨语灵犀爬虫数据智能处理&#xff1a;Python爬虫结果清洗与摘要生成 你是不是也遇到过这种情况&#xff1f;用Python爬虫吭哧吭哧抓了一大堆网页数据&#xff0c;结果打开一看&#xff0c;全是乱码、广告、重复内容&#xff0c;真正有用的信息被埋在里面&#xff0c;找起来费…...

Kimi-VL-A3B-Thinking GPU显存优化部署:2.8B激活参数下的高效多模态服务

Kimi-VL-A3B-Thinking GPU显存优化部署&#xff1a;2.8B激活参数下的高效多模态服务 1. 模型简介与技术亮点 Kimi-VL-A3B-Thinking是一款创新的开源混合专家&#xff08;MoE&#xff09;视觉语言模型&#xff0c;在多模态推理领域展现出卓越性能。该模型最突出的特点是仅激活…...