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

Java线程——常见方法

一、 常见方法

1.1 概述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

start_vs_run:直接调用run方法并不会启动新的线程

import cn.itcast.n2.util.FileReader;
import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test")
public class Test {public static void main(String[] args) {Thread t1 = new Thread("t1"){@Overridepublic void run() {log.debug("running");FileReader.read(Constants.MP4_FULL_PATH);}};t1.run();log.debug("do other things......");}
}

执行结果:直接调用run方法并不会启动新的线程, FileReader.read() 方法调用还是同步的,还是在主线程中调用run,并不能达到提升性能或者异步处理的效果,因此启动一个线程必须要start()。start()启动了线程,再由新的线程去调用run()方法
在这里插入图片描述
结论
● 直接调用 run 是在主线程中执行了 run,没有启动新的线程
● 使用 start 是启动新的线程,通过新的线程间接执行 run 中的代码

sleep与yield

sleep

  1. 调用 sleep 会让当前线程从 Running 进入 Timed Waiting (有时限的等待)状态(阻塞
  2. 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出InterruptedException
  3. 睡眠结束后的线程未必会立刻得到执行
  4. 建议用 TimeUnit(1.5以后新增) 的 sleep 代替 Thread 的 sleep 来获得更好的可读性(其内部也是调用了sleep方法,但其进行了单位的换算使程序可读性更好)

yield

  1. 调用 yield(让出CPU的使用权) 会让当前线程从 Running 进入 Runnable 就绪状态,然后调度执行其它线程
  2. 具体的实现依赖于操作系统的任务调度器

sleep是让线程进入Timed Waiting(阻塞)状态,yield是让线程进入 Runnable(就绪)状态,两个状态表面上都是让线程先不运行,将机会让给其他线程。两者的区别是:
Runnable(就绪)状态:还是有机会被任务调度器调度(任务调度器还是会分时间片给就绪状态的线程)
Timed Waiting(阻塞)状态:任务调度器不会将时间片分给阻塞状态的线程

程序优先级

Thread类中的setPriority()可以设置优先级
在这里插入图片描述

● 线程优先级会提示(hint)调度器优先调度该线程,但它仅仅是一个提示,调度器可以忽略它
● 如果 cpu 比较繁忙,那么优先级高的线程会获得更多的时间片,但 cpu 闲时,优先级几乎没作用

yield与线程优先级并不是很容易控制线程的调度

yield操作示例:(如果以下两个线程同时运行并且被CPU调度的机会均等,则最终的打印结果count值较为接近)

1. 不加任何控制

import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test9")
public class Test9 {public static void main(String[] args) {//  任务对象1(死循环)Runnable task1 = () -> {int count = 0;for (;;) {System.out.println("---->1 " + count++);}};//  任务对象2(死循环)Runnable task2 = () -> {int count = 0;for (;;) {
//                Thread.yield();System.out.println("              ---->2 " + count++);}};Thread t1 = new Thread(task1, "t1");Thread t2 = new Thread(task2, "t2");//      t1.setPriority(Thread.MIN_PRIORITY);//      t2.setPriority(Thread.MAX_PRIORITY);t1.start();t2.start();}
}

被CPU调度机会大致形同
在这里插入图片描述

2. 线程2开启yield()===>线程1得到的时间片就较多进而导致线程1数字增长就较为快些
在这里插入图片描述
线程1、2增长效果差异较为明显

3. 使用优先级,将线程1的优先级设置较低,线程2的优先级较高
在这里插入图片描述
并没有明显效果

总结:无论是yield()还是优先级,他们仅仅是对调度器的一个提示,均不能真正去控制线程任务的调度。最终还是由操作系统的任务调度器来决定哪个线程获得更多的时间片

join

下面代码执行后,打印 r 是什么?

static int r = 0;
public static void main(String[] args) throws InterruptedException {test1();
}private static void test1() throws InterruptedException {log.debug("开始");Thread t1 = new Thread(() -> {log.debug("开始");// 线程1睡眠1秒sleep(1);log.debug("结束");r = 10;});t1.start();log.debug("结果为:{}", r);log.debug("结束");
}

执行结果:
在这里插入图片描述

分析
● 因为主线程和线程 t1 是并行执行的,t1 线程需要 1 秒之后才能算出 r=10
● 而主线程一开始就要打印 r 的结果,所以只能打印出 r=0

解决方法
● 用 sleep 行不行?为什么?
● 用 join,加在 t1.start() 之后即可
在这里插入图片描述

join-同步应用(案例1)

以调用方角度来讲,如果
● 需要等待结果返回,才能继续运行就是同步(上述例子中主线程需要同步等待t1线程结果返回)
● 不需要等待结果返回,就能继续运行就是异步

问,下面代码 cost 大约多少秒?

static int r1 = 0;
static int r2 = 0;
public static void main(String[] args) throws InterruptedException {test2();
}
private static void test2() throws InterruptedException {Thread t1 = new Thread(() -> {sleep(1);r1 = 10;});Thread t2 = new Thread(() -> {sleep(2);r2 = 20;});long start = System.currentTimeMillis();t1.start();t2.start();t1.join();t2.join();long end = System.currentTimeMillis();log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
}

执行结果:(时间差大约为2秒)
在这里插入图片描述

分析如下
● 第一个 join:等待 t1 时, t2 并没有停止, 而在运行
● 第二个 join:1s 后, 执行到此, t2 也运行了 1s, 因此也只需再等待 1s

有时效的 join

1. 未等够时间

import lombok.extern.slf4j.Slf4j;
import static cn.itcast.n2.util.Sleeper.sleep;@Slf4j(topic = "c.Test")
public class Test {static int r1 = 0;static int r2 = 0;public static void main(String[] args) throws InterruptedException {test3();}public static void test3() throws InterruptedException {Thread t1 = new Thread(() -> {sleep(2);r1 = 10;});long start = System.currentTimeMillis();t1.start();log.debug("join begin");// 主线程等待t1运行结束(最多等待1.5s)t1.join(1500);long end = System.currentTimeMillis();log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);}
}

运行结果:(1.5s后主线程便不再等待)

在这里插入图片描述

2. 等够时间

将 t1.join(1500)修改为 t1.join(3000);

运行结果:
在这里插入图片描述
如果线程提前结束,join()也会提前结束,并不会按最大时间等待;若未等够时间,则按时间结束

interrupt-打断

1. 打断阻塞状态的线程
● 打断 sleep,wait,join(这几个方法都会让线程进入阻塞状态) 这些处于阻塞状态的线程,也可以用来打断正在运行状态的线程
* join的底层原理也为wait

打断 sleep 的线程, 会清空打断标记,以 sleep 为例

import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test11")
public class Test11 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {log.debug("sleep...");try {Thread.sleep(5000); // wait, join} catch (InterruptedException e) {e.printStackTrace();}},"t1");t1.start();// 打断正在睡眠的线程,否则t1还未进入睡眠打断的为正常运行下的线程Thread.sleep(1000);log.debug("interrupt");t1.interrupt();// 正常情况下打断标记为ture,反之为falselog.debug("打断标记:{}", t1.isInterrupted());}
}

运行结果:
在这里插入图片描述

阻塞状态的线程被打断后会抛出异常(InterruptedException),打断后还会有一个打断标记(布尔值),表示当前线程是否被其他线程所打断干扰过,但sleep,wait,join它们在被打断后都会将打断标记清空(重置为false)

2. 打断正常运行的线程

打断正常运行的线程,不会打断清空状态

import lombok.extern.slf4j.Slf4j;@Slf4j(topic = "c.Test12")
public class Test12 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread(() -> {while(true) {// 获取当前线程(t1),判断是否被打断boolean interrupted = Thread.currentThread().isInterrupted();if(interrupted) {log.debug("被打断了, 退出循环");break;}}}, "t1");t1.start();Thread.sleep(1000);log.debug("interrupt");// 主线程1s后打断t1线程t1.interrupt();}
}

运行结果:
在这里插入图片描述
打断状态可以用来停止线程

1.2 sleep应用案例(防止CPU占用100%)

sleep实现

while(true)应用:===>在做服务器开发时,编写服务端应用程序需要线程不断运行进而一直接收请求、访问、响应

在没有利用CPU来计算时,不要让while(true)空转浪费CPU,这时可以使用yield或sleep来让出CPU的使用权给其他程序

  while (true){try {// 防止不断利用CPU计算,空转浪费CPU资源(防止对CPU资源的占用)Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}

● 可以用wait或条件变量达到类似的效果
● 不同的是,后两种都需要加锁,并且需要响应的唤醒操作,一般适用于要进行同步的场景
● sleep使用于无需锁同步的场景

相关文章:

Java线程——常见方法

一、 常见方法 1.1 概述 ① start_vs_run:直接调用run方法并不会启动新的线程 import cn.itcast.n2.util.FileReader; import lombok.extern.slf4j.Slf4j;Slf4j(topic "c.Test") public class Test {public static void main(String[] args) {Thread t…...

机器学习:基于逻辑回归对某银行客户违约预测分析

机器学习:基于逻辑回归对某银行客户违约预测分析 文章目录机器学习:基于逻辑回归对某银行客户违约预测分析一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤1.逻辑回归2.业务理解3.读取数据4.数据理解5.数据准备6.逻辑回归模型训练7.模型评…...

MySQL数据库常用命令汇总(全网最全)

目录 数据库常用命令 数据库的创建 数据表的操作 表数据的增删查改 分组与函数查询 运算符:数学运算符 连接查询 多表查询 修改语句 删除语句 字符查询like MySQL练习 总结感谢每一个认真阅读我文章的人!!! 重点&…...

Bulletproofs++

1. 引言 前序博客: Bulletproofs: Short Proofs for Confidential Transactions and More学习笔记Bulletproofs 代码解析Bulletproofs: Shorter Proofs for Privacy-Enhanced Distributed Ledger学习笔记Bulletproofs 代码解析 Liam Eagen 2022年3月论文《Bullet…...

毕业设计(1)-AFLGO的安装

AFLGO是一个模糊测试工具,在CSDN上的安装教程不多,自己在安装过程中也出现了很多教程之外的错误,最后反复安装了2天终于安装成功这里记录一下安装工程中的错误 使用的平台:Ubuntu18.04 配置: 内存:6G&…...

基于Opencv的缺陷检测任务

数据及代码见文末 1.任务需求和环境配置 任务需求:使用opencv检测出手套上的缺陷并且进行计数 环境配置:pip install opencv-python 2.整体流程 首先,我们需要定义几个参数。 图像大小,原图像比较大,首先将图像resize一下再做后续处理图像阈值处理的相应阈值反转阈值的…...

Android Gradle脚本打包

1、背景资料 1.1 Android-Gradle-Groovy-Java-JVM 之间的关系 1.2 Android Gradle Plugin Version版本 与 Gradle Version版本的对应关系 Android Gradle Plugin Version版本Gradle Version版本1.0.0 - 1.1.32.2.1 - 2.31.2.0 - 1.3.12.2.1 - 2.91.5.02.2.1 - 2.132.0.0 -…...

平滑KDJ指标公式,减少无效金叉死叉

软件自带的KDJ指标比较敏感,在震荡上涨或者震荡下跌时会反复出现金叉死叉信号,不利于指标的使用以及进一步开发。为了减少无效金叉死叉,本文对KDJ指标公式进行平滑处理。 一、KDJ指标对比 以下为软件自带的KDJ指标,加上了图标。本…...

大势前瞻!文旅还是短视频,你弯道超车风口在这了

三年前,新冠疫情的影响波及整个各行各业行业,互联网寒冬,房地产崩盘,教培团灭,在这样的背景下,行业都进入了发展“冰雪期”。老话说大疫后必有大变,如今风雪融化,万物复苏&#xff0…...

JAVA基础常见面试题

1.Java接口和抽象类的区别? 接口 接口中不能定义构造器 方法全部都是抽象方法,JDK8提供方法默认实现 接口中的成员都是public的 接口中定义的成员变量实际上都是常量 一个类可以实现多个接口 抽象类 抽象类中可以定义构造器 可以有抽象方法和具体…...

通过一张照片来定位拍摄地点和网站的域名 LA CTF 2023

简介 这次打ctf遇到了一个比较经典的osint类题目,在这里分享一下如何做此类题目 题目链接: https://platform.lac.tf/challs题目简介: 你能猜出这个猫天堂的名字吗?答案是此位置的网站域。例如,如果答案是 ucla&…...

SpringBoot(powernode)(内含教学视频+源代码)

SpringBoot(powernode)(内含教学视频源代码) 教学视频源代码下载链接地址:https://download.csdn.net/download/weixin_46411355/87484637 目录SpringBoot(powernode)(内含教学视频…...

TEMU联盟计划用意何在?做推广达人真的能收入满满吗?

据东哥近期了解,Temu在北美市场表现十分火爆,甚至冲上了AppStore下载榜第一名。Temu在美国市场上采用了类似PDD的病毒式传播策略,以实惠的产品和折扣吸引消费者并动员普通人大量传播链接和App下载,所以有了TEMU联盟计划&#xff0…...

【概念辨析】二维数组传参的集中可能性

一、二维数组传参竟然不是用二级指针进行接收? 今天进行再一次的二级指针学习时,发现了一条以前没怎么注意过的知识点:二维数组进行传参只能用二维数组(不能省略列)进行接收或者是数组指针。 问题复现代码如下&#xf…...

Photon Vectorized Engine 学习记录

Photon Hash Aggregation Vectorization Photon Hash Join 的向量化的要点是:使用开放地址法。步骤: 向量化计算 hash 值基于 hash 向量化计算 bucket 下标,得到 bucket index 向量基于 bucket index 向量中记录的下标找到 bucket&#xff…...

webRTC学习-基础知识

webRTC学习1、webRTC简介1.1什么是webRTC?1.2、作用2、webRTC通信原理2.1、媒体协商(SDP)2.2、网络协商(candidate)2.2.1、STUN2.2.2、TURN2.3、媒体协商网络协商数据的交换通道webRTC官网1、webRTC简介 1.1什么是web…...

MySQL数据库——JDBC编程

文章目录一、什么是Java的JDBC二、JDBC编程三、代码整体展示一、什么是Java的JDBC JDBC,即Java Database Connectivity。意思是java数据库连接。是一种用来执行 SQL 语句的 JavaAPI,是Java中数据库的连接规范。这个 API 由 java.sql* 和 javax.sql* 包中…...

【面向小白】你见过这样讲解队列的吗?(阅此文可学会用纯C手撕一个队列)

目录 0.前言 1.什么是队列 2.选择什么结构实现队列 3.用C语言实现队列 3.1用什么可以封装代表一个队列 3.2队列接口的设计 3.3 队列的初始化 3.4 队列的销毁 3.5* 队列的状态分析 3.6 队列的插入 3.7 队列的删除 3.8 队列的大小(有效元素的数目&#xff…...

[element plus] 对话框组件再封装使用 - vue

学习关键语句: 饿了么组件dialog组件使用 dialog组件二次封装 vue3中封住的组件使用update触发更新 vue3中封装组件使用v-model:属性值来传值 写在前面 这是我遇到的一个页面需求 , 其中一个对话框的内容是很常用的 , 所以我将它封装出来才写的一篇文章 现在给出如下需求: 封…...

Markdown基本语法简介

前言:当你在git平台创建一个仓库时,平台会自动创建一个README.md文件,并将它的内容展现在web端页面,方面其他读者查阅。README.md实则是一个适用Markdown语法的文本文件,从他的后缀md即可看出它是Markdown的缩写。在gi…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望

文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

Mac软件卸载指南,简单易懂!

刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"&#xff0…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...

如何在网页里填写 PDF 表格?

有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据&#xff…...

Java编程之桥接模式

定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...