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

【JAVAEE】多线程

【JAVAEE】多线程

  • 一、进程
      • 1.1 进程的定义
      • 1.2 进程和线程的联系
  • 二、线程
      • 2.1 JConsole工具
      • 2.2 创建线程
        • 2.2.1 Thread类,start(),run()
        • 2.2.2 继承Thread类
        • 2.2.3 实现Runnable接口
        • 2.2.4 匿名内部类
        • 2.2.5 使用Runnable接口的匿名内部类
        • 2.2.6 使用lambda表达式
      • 2.3 Thread类及常用方法
        • 2.3.1 Thread类的构造方法
        • 2.3.2 Thread类的常见属性
      • 2.4 线程状态
      • 2.5 后台线程和前台线程
      • 2.6 休眠线程
      • 2.7 线程等待
      • 2.8 终止线程
        • 2.8.1 自定义标志位终止线程
        • 2.8.2 使用自带标志位终止线程

博客结尾包含此篇博客的全部代码!!!

一、进程

1.1 进程的定义

  • 进程(Process)是计算机操作系统中的一个核心概念,它是程序在计算机上的一次动态执行实例。换句话说,进程是程序运行时的活动表现形式。它包含了程序代码、数据、运行状态以及系统资源的分配情况。进程相当于一个正在运行的程序
  • 进程也是系统分配资源的基本单位

在这里插入图片描述

1.2 进程和线程的联系

首先,并发编程成为我们的需求!每个客户端给服务器发送请求,服务器就需要给客户端提供服务。在90年代,多进程是一种解决方案!!!

那么既然有解决方法,为什么还要引入线程?
线程:线程是轻量级的进程!!!

线程相比于进程:

  • 创建线程比创建进程更快。
  • 销毁线程比销毁进程更快。
  • 调度线程比调度进程更快。

举个例子:

假设这个任务是“消灭”桌子上的两只鸡,在一个房间中有一个桌子,桌子上放了两只鸡。
进程的解决方法:再创建一个房间,将这两只鸡分开,分别“消灭”。
在这里插入图片描述
线程的解决方法:在这个房间中“消灭”这两只鸡。
在这里插入图片描述
这两个对比你发现:相同的人数,进程需要再创建一个房间(开销很大),而线程则啥都不需要添加。

二、线程

2.1 JConsole工具

在创建线程之前,先给大家介绍一下JConsole 工具, JConsole是JDK 自带的一款图形化监控和管理工具,基于 JMX(Java Management Extensions)技术实现。它能够连接到本地或远程的 Java 虚拟机(JVM),并实时监控和管理 Java 应用程序的性能和资源使用情况。
这里我们就用它来监控我们的线程!
JConsole:找到我们的JDK安装的安装路径,像我这里安装的JDK17–>bin–>jconsole.exe
在这里插入图片描述
如何使用?
测试代码:代码运行起来才能观察到,如果线程结束就观察不到。

class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println(" hello Thread");}}
}public class Demo1 {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();}
}

在这里插入图片描述

在这里插入图片描述
刚进去出现不安全连接,由于是我是自己练习,所以点不安全连接。
在这里插入图片描述

2.2 创建线程

2.2.1 Thread类,start(),run()
  • Thread类:线程,是操作系统的概念,操作系统定义了一些api(应用程序编程接口)来供程序员使用,而java中将这些api封装成Thread类来供使用!Thread类在java.long这个包中,所以用的时候不需要导包。
  • start():用于启动一个新线程,线程调度器会调用 run() 方法。start() 方法只能被调用一次。如果尝试多次调用 start(),会抛出 IllegalThreadStateException 异常。
  • run():定义线程的执行逻辑,但不会启动新线程。如果需要启动新线程,必须通过 start() 方法。相当于线程的入口。
2.2.2 继承Thread类

代码:

class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println(" hello Thread");}}
}public class Demo1 {public static void main(String[] args) {MyThread t1 = new MyThread();t1.start();while(true) {System.out.println(" hello main");}}
}
2.2.3 实现Runnable接口

实现Runnable接口的MyRunnnable类,将new MyRunnable()当作一个对象传给Thread的构造函数。
代码:

class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Hello Thread");}
}public class Demo2 {public static void main(String[] args) {Thread t1 = new Thread(new MyRunnable());t1.start();}
}
2.2.4 匿名内部类
public class Demo3 {public static void main(String[] args) {Thread thread = new Thread(){@Overridepublic void run() {System.out.println("Hello Thread");}};thread.start();System.out.println("Hello main");}
}
2.2.5 使用Runnable接口的匿名内部类
public class Demo4 {public static void main(String[] args) {Thread t1 = new Thread(new Runnable(){@Overridepublic void run() {System.out.println("Hello Thread");}});t1.start();}
}
2.2.6 使用lambda表达式
public class Demo5 {public static void main(String[] args) {Thread thread = new Thread(()->{while(true){System.out.println("Hello Thread");}});thread.start();while(true){System.out.println("Hello main");}}
}

2.3 Thread类及常用方法

2.3.1 Thread类的构造方法

在这里插入图片描述
解释一下第四个Thread(Runnable target,String name)!


public class Demo6 {public static void main(String[] args) {Thread thread = new Thread(new Runnable() {@Overridepublic void run() {while (true) {System.out.println("Hello Thread");}}}, "Thread1");thread.start();while (true) {System.out.println("Hello main");}}
}

在这里插入图片描述

在这里插入图片描述

2.3.2 Thread类的常见属性

在这里插入图片描述
• ID 是线程的唯⼀标识,不同线程不会重复
• 获取线程的名称
• 获取线程的当前状态,如新建、就绪、运行、阻塞、等待、终止等
• 优先级⾼的线程理论上来说更容易被调度到
• 关于后台线程,需要记住⼀点:JVM会在⼀个进程的所有⾮后台线程结束后,才会结束运⾏。
• 是否存活,即简单的理解,为 run ⽅法是否运⾏结束了
• 判断线程是否被中断。线程的中断状态可以通过调用 interrupt() 方法来设置,该方法会改变线程的中断状态,但不会停止线程的执行

2.4 线程状态

public class Demo7 {public static void main(String[] args) {for(Thread.State state: Thread.State.values()) {System.out.println(state);}}
}

获取线程的所有状态:
在这里插入图片描述
• NEW:

  • 当线程对象被创建,但尚未调用 start() 方法时,线程处于新建状态。
  • 在这个状态下,线程尚未开始执行。
public class Demo7 {public static void main(String[] args) {Thread thread=new Thread(()->{System.out.println("Hello Thread");});System.out.println(thread.getState());thread.start();}
}

• RUNNABLE:

  • 当调用线程的 start() 方法后,线程进入就绪状态。
  • 在这个状态下,线程已经准备好运行,等待 CPU 时间片以便执行。
  • 就绪状态的线程可能正在 JVM 中运行,也可能正在等待操作系统调度。
public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(()->{for(int i=0;i<3;i++) {System.out.println("Hello Thread");}});System.out.println(thread.getState());thread.start();System.out.println(thread.getState());}
}

• BLOCKED: 由锁导致的,后面会出一篇关于线程安全问题,到时候会详细介绍,这里就不过多介绍了

  • 当线程等待获取一个排他锁,如同步块或同步方法中的锁时,线程进入阻塞状态。
  • 线程在等待锁释放后才能继续执行。
  • 阻塞状态的线程不会被分配 CPU 时间片。

• WAITING:
时间阻塞(这个等待是没时间上限的)

  • 当线程执行 wait()、join() 或 LockSupport.park() 方法后,线程进入等待状态。
  • 在这个状态下,线程需要等待其他线程执行特定的操作(如通知或中断)才能继续。
  • 等待状态的线程不会被分配 CPU 时间片。
public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(()->{while(true) {}});System.out.println(thread.getState());thread.start();thread.join();}
}

在这里插入图片描述
发现main线程是waiting。

• TIMED_WAITING:
时间阻塞(这个等待是有时间上限的),不参与CPU调度

public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(()->{while(true) {try {Thread.sleep(2000);} catch (InterruptedException e) {throw new RuntimeException(e);}}});System.out.println(thread.getState());thread.start();Thread.sleep(1000);System.out.println(thread.getState());}
}

• TERMINATED:

  • 当线程的 run() 方法执行完毕,或者线程被 stop() 方法(已废弃)强制停止,或者线程抛出未捕获的异常导致运行结束时,线程进入终止状态。
  • 在这个状态下,线程已经结束执行,不再消耗任何资源。
public class Demo7 {public static void main(String[] args) throws InterruptedException {Thread thread=new Thread(()->{for(int i=0;i<3;i++) {System.out.println("Hello Thread");}});System.out.println(thread.getState());thread.start();Thread.sleep(6000);System.out.println(thread.getState());}
}

2.5 后台线程和前台线程

前台线程:一般我们创建的线程都是前台线程,只要前台线程不结束,JVM就不会退出。
后台线程:也称守护线程,后台线程一般都是辅助性的任务,如果前台线程全部结束,即使还有后台线程在运行,JAM也会退出。

public class Demo8 {public static void main(String[] args) {Thread thread1=new Thread(()->{for(int i=0;i<2;i++){System.out.println("Hello Thread");}});thread1.start();System.out.println(thread1.isDaemon());//false 说明他不是守护线程Thread thread2=new Thread(()->{for(int i=0;i<2;i++){System.out.println("Hello Thread");}});thread2.setDaemon(true);thread2.start();System.out.println(thread2.isDaemon());//true}
}

2.6 休眠线程

在这里插入图片描述
下面那个可以达到纳秒级别,这种适用于军工,航天等之类,一把情况下用不到。
在这里插入图片描述
这里还有一个需要注意的是:由于 Runnable 接口的 run 方法没有 throws 子句,所以这里只能用try-catch 来捕获异常。

2.7 线程等待

在这里插入图片描述

public class Demo10 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{for (int i = 0; i < 3; i++){System.out.println("Hello Thread");}});thread.start();thread.join();System.out.println("Hello main");}
}

先执行thread线程,thread线程执行完,再执行main线程。为了防止死等,也可以设置等待时间。

2.8 终止线程

让run方法尽快结束。

2.8.1 自定义标志位终止线程
public class Demo11 {public static  boolean flag=true;public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(()->{while(flag){System.out.println("Hello Thread");}System.out.println("Bye Bye Thread");});thread.start();Thread.sleep(1000);flag=false;}
}

将flag设置为全局变量,这里就是匿名内部类访问外部类,而不是变量捕获。
为什么不可以将flag设置为局部变量?
在这里插入图片描述

很有可能是main线程已经执行完,已经将flag销毁了,但是Thread线程中还没执行到while(flag)…

2.8.2 使用自带标志位终止线程

在这里插入图片描述
Java自带标志位来结束终止线程。先使用Thread.currentThread()来获取当前线程,在.isInterrupted()获取标志位。然后再主进程中调用interrupte()方法来将标志位值修改为true。

public class Demo12 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() -> {while (!Thread.currentThread().interrupted()) {System.out.println("Hello Thread");}System.out.println("Bye Bye Thread");});thread.start();Thread.sleep(1000);thread.interrupt();}
}

调用interrupte()方法,不仅会设置标志位,还会提前唤起sleep阻塞

public class Demo12 {public static void main(String[] args) throws InterruptedException {Thread thread = new Thread(() ->{while (!Thread.currentThread().isInterrupted()) {System.out.println("hahah");try {Thread.sleep(1000);} catch (InterruptedException e) {//1.不操作继续执行线程(因为sleep唤醒后会又将标志位改为true)e.printStackTrace();//2.结束线程break;//3.进行其它操作}}});thread.start();Thread.sleep(1000);thread.interrupt();}
}

此篇博客的全部代码!!!

相关文章:

【JAVAEE】多线程

【JAVAEE】多线程 一、进程1.1 进程的定义1.2 进程和线程的联系 二、线程2.1 JConsole工具2.2 创建线程2.2.1 Thread类&#xff0c;start&#xff08;&#xff09;&#xff0c;run&#xff08;&#xff09;2.2.2 继承Thread类2.2.3 实现Runnable接口2.2.4 匿名内部类2.2.5 使用…...

5.10 P-Tuning v2:多层级提示编码的微调革新

P-Tuning v2:多层级提示编码的微调革新 一、技术架构解析 #mermaid-svg-4Wy6vkXZi67hY9PZ {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-4Wy6vkXZi67hY9PZ .error-icon{fill:#552222;}#mermaid-svg-4Wy6vkXZi67h…...

LLM中的Benchmark是什么

LLM中的Benchmark是什么 “DeepSeek推动价值重估Benchmark” DeepSeek这家公司或其相关技术的发展,促使Benchmark这家机构对相关资产或企业的价值进行重新评估。“Benchmark”在这里是一家研究机构或金融分析机构。 “Benchmark”常见的意思是“基准;水准点,基准点”,作…...

PMP项目管理—整合管理篇—6.实施整体变更控制

文章目录 基本信息4W1HITTO输入工具与技术输出 变更请求请求时间修改内容变更来源变更类型 实施已批准变更的形式纠正措施预防措施缺陷补救更新 变更控制工具 实施整体变更控制规则态度规则项目变更控制委员会&#xff08;CCB&#xff09;变更应对分析计划、执行期后期或收尾 基…...

深度学习之特征提取

前言 深度学习就是把输入转换成一个高维的向量&#xff0c;之后利用这个向量去完成分类、回归等任务。 深度学习特征工程知识图谱 1. 特征提取的本质 核心目标&#xff1a;将原始数据→高维语义特征向量 监督驱动&#xff1a;标签决定特征提取方向 典型架构&#xff1a; …...

Gurobi 并行计算的一些问题

最近尝试用 gurobi 进行并行计算&#xff0c;即同时用多个 cpu 核计算 gurobi 的 model&#xff0c;但是发现了不少问题。总体来看&#xff0c;gurobi 对并行计算的支持并不是那么好。 gurobi 官方对于并行计算的使用在这个网址&#xff0c;并有下面的大致代码&#xff1a; i…...

堆、栈、最小堆

堆是什么 结构属性 堆是一棵完全二叉树&#xff0c;即除最后一层外&#xff0c;其他层节点均填满&#xff0c;且最后一层节点从左到右连续分布。 排序属性&#xff1a; 根据类型不同&#xff0c;堆分为&#xff1a; 最大堆&#xff08;Max-Heap&#xff09; &#xff1a;每…...

基于 Spring AI 的 HIS 系统智能化改造

【Spring AI 的背景与现状】 Spring AI 是 Spring 生态里整的一个新活儿&#xff0c;专门给开发者提供搞 AI 驱动的应用的工具和框架。虽然 Spring AI 已经鼓捣了挺长时间&#xff0c;但截至现在&#xff08;2025年2月&#xff09;&#xff0c;它还没正式发布。不过&#xff0…...

React进阶之前端业务Hooks库(五)

前端业务Hooks库 Hooks原理useStateuseEffect上述问题useState,useEffect 复用的能力练习:怎样实现一套React过程中的hooks状态 & 副作用Hooks原理 不能在循环中、条件判断、子函数中调用,只能在函数最外层去调用useEffect 中,deps 为空,执行一次useState 使用: imp…...

常见锁类型介绍

下面结合代码详细介绍 Mutex、RW Lock、Futex、自旋锁、信号量、条件变量 和 synchronized&#xff0c;并分析它们的适用场景、特点以及为什么这些锁适用于特定场景。我们将从锁的实现机制和性能特点出发&#xff0c;解释其适用性。 1. Mutex&#xff08;互斥锁&#xff09; 代…...

Java中,Scanner和System.out超时的解决方法及原理

ACM 模式的原理 在输入输出的时候&#xff0c;会先将输入输出的东西放在一个文件里&#xff0c;这个文件也叫做 IO 设备 为什么 Scanner 会慢 new 一个 Scanner &#xff0c;在 Scanner 里面调用 next 的时候&#xff0c;程序会直接访问 IO 设备。在调用一个 next 的时候&…...

一种数据高效具身操作的原子技能库构建方法

25年1月来自京东、中科大、深圳大学、海尔集团、地平线机器人和睿尔曼智能科技的论文“An Atomic Skill Library Construction Method for Data-Efficient Embodied Manipulation”。 具身操控是具身人工智能领域的一项基本能力。尽管目前的具身操控模型在特定场景下表现出一定…...

云创智城YunCharge 新能源二轮、四轮充电解决方案(云快充、万马爱充、中电联、OCPP1.6J等多个私有单车、汽车充电协议)之新能源充电行业系统说明书

云创智城YunCharge 新能源充电行业系统说明书 ⚡官方文档 ⚡官网地址 1. 引言 随着全球环境保护和能源危机的加剧&#xff0c;新能源汽车行业得到了快速发展&#xff0c;充电基础设施建设也随之蓬勃发展。新能源充电行业系统旨在提供高效、便捷的充电服务&#xff0c;满足电…...

JVM垃圾回收器深度底层原理分析与知识体系构建

一、垃圾回收的基本步骤 标记&#xff08;Marking&#xff09; 从GC Roots&#xff08;如虚拟机栈、方法区静态变量、本地方法栈等&#xff09;出发&#xff0c;遍历对象引用链&#xff0c;标记所有可达对象为存活对象&#xff0c;未被标记的则视为垃圾。此阶段需暂停用户线程&…...

30.[前端开发-JavaScript基础]Day07-数组Array-高阶函数-日期Date-DOM

JavaScript的DOM操作 &#xff08;一&#xff09; 1 什么是DOM&#xff1f; 认识DOM和BOM 深入理解DOM 2 认识DOM Tree DOM Tree的理解 3 DOM的整体结构 DOM的学习顺序 DOM的继承关系图 document对象 4 节点、元素导航 节点&#xff08;Node&#xff09;之间的导航&…...

IP、网关、子网掩码、DNS 之间的关系详解

IP、网关、子网掩码、DNS 之间的关系详解 在计算机网络中&#xff0c;IP、网关、子网掩码和 DNS 是几个关键概念&#xff0c;它们协同工作&#xff0c;共同保障网络通信的顺畅。本文将详细探讨它们之间的关系。 一、IP 地址 IP 地址是网络中设备的唯一标识&#xff0c;如同现…...

【Day50 LeetCode】图论问题 Ⅷ

一、图论问题 Ⅷ 1、dijkstra算法 堆优化 采用堆来优化&#xff0c;适合节点多的稀疏图。代码如下&#xff1a; # include<iostream> # include<vector> # include<list> # include<queue> # include<climits>using namespace std;class myco…...

结构体介绍及内存大小分配问题

结构体 一.结构体的介绍1.1结构体的声明1.2匿名结构体1.3结构的自引用1.4使用 typedef 简化结构体类型名 二.结构体内存对齐2.1内存对齐规则2.2结构体内存对齐原因2.3修改默认对齐数 在 C 语言中&#xff0c;结构体&#xff08;struct&#xff09;是一种用户自定义的数据类型&a…...

halcon 条形码、二维码识别、opencv识别

一、条形码 函数介绍 create_bar_code_model * 1.创建条码读取器的模板 * 参数一&#xff1a;通用参数的名称&#xff0c;针对条形码模型进行调整。默认值为空 * 参数二&#xff1a;针对条形码模型进行调整 * 参数三&#xff1a;条形码模型的句柄。 create_bar_code_model (…...

Vue框架的使用 搭建打包 Vue的安全问题(Xss,源码泄露)

前言 什么是Vue&#xff1f; Vue是轻量级的js框架 可以帮助我们一键构造网站&#xff0c;打包app程序等 Vue的基本使用 1、构造框架并启用 新建一个 目录 使用终端切换到当前的目录 创建vue项目 第一个弹出使用语法我们选择是 剩下的全选择否 发现创建好了 接着进行…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

什么是Ansible Jinja2

理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具&#xff0c;可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板&#xff0c;允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板&#xff0c;并通…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

JS手写代码篇----使用Promise封装AJAX请求

15、使用Promise封装AJAX请求 promise就有reject和resolve了&#xff0c;就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...