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 的常见属性
属性 | 获取方法 |
ID | getId() |
名称 | 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() 的区别
作用功能:
- start()方法内部是会调用系统的API,在系统内核创建一个线程
- run()方法只是描述线程具体实现的任务(会在start创建好之后会自动被调用)
运行结果:
- start调用方法后, start方法内部会调用Java 本地方法(封装了对系统底层的调用)真正的启动线程,并执行run方法中的代码,run 方法执行完成后线程进入销毁阶段。
- 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}
}
注:
- 如果没有sleep,就不会出现上述情况,线程会直接退出!!!
- 我们不建议使用 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("等待结束");}
}
注:
- 要分清哪个线程是等待的,哪个线程是被等待的
- 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)
一,创建线程 方法一:继承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 结构概念 结构是一些值的集合,这些值称为…...

【网络】HTTPS的加密
目录 第一组,非对称加密第二组,非对称加密第三组,对称加密证书签名 HTTPS使用的是非对称加密加对称加密的方案 (非对称加密:公钥加/解密,私钥解/加密) (对称加密:一组对称…...

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

java-Optional 类详解
目录 前言 Optional的构造方法 Optional的相关方法介绍 isPresent用法: get用法: filter用法: orElse用法: orElseGet用法 orElseThrow用法 map用法 flatMap用法: 前言 Optional 类是java8的新特性࿰…...

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

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

Java“牵手”天猫淘口令转换API接口数据,天猫API接口申请指南
天猫平台商品淘口令接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取天猫商品的标题、价格、库存、商品快递费用,宝贝ID,发货地,区域ID,快递费用,月销量、总销量、库存、详情描…...

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.代码内容复现不考虑空气阻力考虑空气阻力模型 数学建模背景 首先先简单的介绍数学建模是一个怎么样的内容 数学建模是一种将数…...

局域网中电脑共享文件给手机
学习资源: 局域网共享:这样设置,你可以轻松拷贝任何电脑的文件。_哔哩哔哩_bilibili 可以实现什么效果? 连接同一个WIFI,电脑端为服务端,提供共享文件,手机是客户端,可以读取服务端…...
线段树练习
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.分页
介绍: 动态SQL是MyBatis提供的一种动态生成SQL语句的方式,可以根据不同的条件生成不同的SQL语句,从而实现更加灵活的查询和操作。 在MyBatis的映射文件中,可以通过使用if、choose、when、otherwise、foreach等标签来实现动态SQL…...
springboot向resources下写文件的两种方式
文章目录 方式一:方式二: 方式一: 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网卡开发:openonload 安装与调试_openonload安装_Erice_s的博客-CSDN博客 cns-sfnettest测试 cns-sfnettest 下载 https://github.com/Xilinx-CNS/cns-sfnettes…...
Redis知识点整理
第一部分:Redis基础知识点 1、数据类型 5种常用基础类型:string,hash,list,set,zset – 字符串,Hash表,List顺序集合,Set无序集合,ZSet有序集合3中特殊类型:bitmap-字节地图, hyperloglog-统计…...

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

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

【ArcGIS Pro二次开发】(62):复制字段
应网友需求,做了这么一个复制字段的小工具。 假定这样一个场景,手头有一个要素1,要素里有10个字段,另一个要素2,除了shape_area等图形字段外,没有其它字段。 现在的需求是,想把要素1中的8个字…...

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

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

Chapter03-Authentication vulnerabilities
文章目录 1. 身份验证简介1.1 What is authentication1.2 difference between authentication and authorization1.3 身份验证机制失效的原因1.4 身份验证机制失效的影响 2. 基于登录功能的漏洞2.1 密码爆破2.2 用户名枚举2.3 有缺陷的暴力破解防护2.3.1 如果用户登录尝试失败次…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...

Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

零知开源——STM32F103RBT6驱动 ICM20948 九轴传感器及 vofa + 上位机可视化教程
STM32F1 本教程使用零知标准板(STM32F103RBT6)通过I2C驱动ICM20948九轴传感器,实现姿态解算,并通过串口将数据实时发送至VOFA上位机进行3D可视化。代码基于开源库修改优化,适合嵌入式及物联网开发者。在基础驱动上新增…...