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

Java并发编程面试题:ThreadLocal(8题)

🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea

在这里插入图片描述


在这里插入图片描述

Java并发编程面试题:ThreadLocal

1. ThreadLocal 是什么?

ThreadLocal是 Java 中提供的一种用于实现线程局部变量的工具类。它允许每个线程都拥有自己的独立副本,从而实现线程隔离,用于解决多线程中共享对象的线程安全问题。

在这里插入图片描述

在 Web 应用中,可以使用 ThreadLocal 存储用户会话信息,这样每个线程在处理用户请求时都能方便地访问当前用户的会话信息。

在数据库操作中,可以使用 ThreadLocal 存储数据库连接对象,每个线程有自己独立的数据库连接,从而避免了多线程竞争同一数据库连接的问题。

在格式化操作中,例如日期格式化,可以使用 ThreadLocal 存储 SimpleDateFormat 实例,避免多线程共享同一实例导致的线程安全问题。

使用 ThreadLocal 通常分为四步:

①、创建 ThreadLocal

//创建一个ThreadLocal变量
public static ThreadLocal<String> localVariable = new ThreadLocal<>();

②、设置 ThreadLocal 的值

//设置ThreadLocal变量的值
localVariable.set("沉默王二是沙雕");

③、获取 ThreadLocal 的值

//获取ThreadLocal变量的值
String value = localVariable.get();

④、删除 ThreadLocal 的值

//删除ThreadLocal变量的值
localVariable.remove();

ThreadLocal 有哪些优点?

①、线程隔离:每个线程访问的变量副本都是独立的,避免了共享变量引起的线程安全问题。由于 ThreadLocal 实现了变量的线程独占,使得变量不需要同步处理,因此能够避免资源竞争。

②、数据传递方便:ThreadLocal 常用于在跨方法、跨类时传递上下文数据(如用户信息等),而不需要在方法间传递参数。

除了 ThreadLocal,还有什么解决线程安全问题的方法?

①、Java 中的 synchronized 关键字可以用于方法和代码块,确保同一时间只有一个线程可以执行特定的代码段。

public synchronized void method() {// 线程安全的操作
}

②、Java 并发包(java.util.concurrent.locks)中提供了 Lock 接口和一些实现类,如 ReentrantLock。相比于 synchronized,ReentrantLock 提供了公平锁和非公平锁。

ReentrantLock lock = new ReentrantLock();public void method() {lock.lock();try {// 线程安全的操作} finally {lock.unlock();}
}

③、Java 并发包还提供了一组原子变量类(如 AtomicInteger,AtomicLong 等),它们利用 CAS(比较并交换),实现了无锁的原子操作,适用于简单的计数器场景。

AtomicInteger atomicInteger = new AtomicInteger(0);public void increment() {atomicInteger.incrementAndGet();
}

④、Java 并发包提供了一些线程安全的集合类,如 ConcurrentHashMap,CopyOnWriteArrayList 等。这些集合类内部实现了必要的同步策略,提供了更高效的并发访问。

ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();

⑤、volatile 变量保证了变量的可见性,修改操作是立即同步到主存的,读操作从主存中读取。

private volatile boolean flag = false;

2. 你在工作中用到过 ThreadLocal 吗?

有用到过,用来存储用户信息。

MVC 架构,登录后的用户每次访问接口,都会在请求头中携带一个 token,在控制层可以根据这个 token,解析出用户的基本信息。

假如在服务层和持久层也要用到用户信息,就可以在控制层拦截请求把用户信息存入 ThreadLocal。

技术派实战源码

这样我们在任何一个地方,都可以取出 ThreadLocal 中存的用户信息。

技术派实战源码

很多其它场景的 cookie、session 等等数据隔离都可以通过 ThreadLocal 去实现。

在这里插入图片描述

数据库连接池也可以用 ThreadLocal,将数据库连接池的连接交给 ThreadLocal 进行管理,能够保证当前线程的操作都是同一个 Connnection。

3. ThreadLocal 怎么实现的呢?

ThreadLocal 本身并不存储任何值,它只是作为一个映射,来映射线程的局部变量。当一个线程调用 ThreadLocal 的 set 或 get 方法时,实际上是访问线程自己的 ThreadLocal.ThreadLocalMap。

二哥的 Java 进阶之路:ThreadLocalMap

ThreadLocalMap 是 ThreadLocal 的静态内部类,它内部维护了一个 Entry 数组,key 是 ThreadLocal 对象,value 是线程的局部变量本身。

在这里插入图片描述

早期的 ThreadLocal 不是这样的,它的 ThreadLocalMap 中使用 Thread 作为 key,这也是最简单的实现方式。

黑马:JDK 早期设计

优化后的方案有两个好处,一个是 Map 中存储的键值对变少了;另一个是 ThreadLocalMap 的生命周期和线程一样长,线程销毁的时候,ThreadLocalMap 也会被销毁。

Entry 继承了 WeakReference,它限定了 key 是一个弱引用,弱引用的好处是当内存不足时,JVM 会回收 ThreadLocal 对象,并且将其对应的 Entry 的 value 设置为 null,这样在很大程度上可以避免内存泄漏。

static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;//节点类Entry(ThreadLocal<?> k, Object v) {//key赋值super(k);//value赋值value = v;}
}

ThreadLocal 的实现原理就是,每个线程维护一个 Map,key 为 ThreadLocal 对象,value 为想要实现线程隔离的对象。

1、当需要存线程隔离的对象时,通过 ThreadLocal 的 set 方法将对象存入 Map 中。

2、当需要取线程隔离的对象时,通过 ThreadLocal 的 get 方法从 Map 中取出对象。

3、Map 的大小由 ThreadLocal 对象的多少决定。

在这里插入图片描述

什么是弱引用,什么是强引用?

强引用,比如说 User user = new User("沉默王二") 中,user 就是一个强引用,new User("沉默王二") 就是一个强引用对象。

当 user 被置为 null 时(user = null),new User("沉默王二") 将会被垃圾回收;如果 user 不被置为 null,即便是内存空间不足,JVM 也不会回收 new User("沉默王二") 这个强引用对象,宁愿抛出 OutOfMemoryError。

弱引用,比如说下面这段代码:

ThreadLocal<User> userThreadLocal = new ThreadLocal<>();
userThreadLocal.set(new User("沉默王二"));

①、userThreadLocal 是一个强引用,new ThreadLocal<>() 是一个强引用对象;

②、new User("沉默王二") 是一个强引用对象。

③、在 ThreadLocalMap 中,key = new ThreadLocal<>() 是一个弱引用对象。当 JVM 进行垃圾回收时,如果发现了弱引用对象,就会将其回收。

在这里插入图片描述

其关系链就是:

  • ThreadLocal 强引用 -> ThreadLocal 对象。
  • Thread 强引用 -> ThreadLocalMap。
  • ThreadLocalMap[i] 强引用了 -> Entry。
  • Entry.key 弱引用 -> ThreadLocal 对象。
  • Entry.value 强引用 -> 线程的局部变量对象。

4. ThreadLocal 内存泄露是怎么回事?

通常情况下,随着线程 Thread 的结束,其内部的 ThreadLocalMap 也会被回收,从而避免了内存泄漏。

但如果一个线程一直在运行,并且其 ThreadLocalMap 中的 Entry.value 一直指向某个强引用对象,那么这个对象就不会被回收,从而导致内存泄漏。当 Entry 非常多时,可能就会引发更严重的内存溢出问题。

在这里插入图片描述

那怎么解决内存泄漏问题呢?

很简单,使用完 ThreadLocal 后,及时调用 remove() 方法释放内存空间。

try {threadLocal.set(value);// 执行业务操作
} finally {threadLocal.remove(); // 确保能够执行清理
}

remove() 方法会将当前线程的 ThreadLocalMap 中的所有 key 为 null 的 Entry 全部清除,这样就能避免内存泄漏问题。

private void remove(ThreadLocal<?> key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {e.clear();expungeStaleEntry(i);return;}}
}public void clear() {this.referent = null;
}

那为什么 key 要设计成弱引用?

弱引用的好处是,当内存不足的时候,JVM 会主动回收掉弱引用的对象。

比如说:

WeakReference key = new WeakReference(new ThreadLocal());

key 是弱引用,new WeakReference(new ThreadLocal()) 是弱引用对象,当 JVM 进行垃圾回收时,如果发现了弱引用对象,就会将其回收。

一旦 key 被回收,ThreadLocalMap 在进行 set、get 的时候就会对 key 为 null 的 Entry 进行清理。

在这里插入图片描述

总结一下,在 ThreadLocal 被垃圾收集后,下一次访问 ThreadLocalMap 时,Java 会自动清理那些键为 null 的条目(参照源码中的 replaceStaleEntry 方法),这个过程会在执行 ThreadLocalMap 相关操作(如 get(), set(), remove())时触发。

 Java 进阶之路

你了解哪些 ThreadLocal 的改进方案?

在 JDK 20 Early-Access Build 28 版本中,出现了 ThreadLocal 的改进方案,即 ScopedValue

还有 Netty 中的 FastThreadLocal,它是 Netty 对 ThreadLocal 的优化,它内部维护了一个索引常量 index,每次创建 FastThreadLocal 中都会自动+1,用来取代 hash 冲突带来的损耗,用空间换时间。

private final int index;public FastThreadLocal() {index = InternalThreadLocalMap.nextVariableIndex();
}
public static int nextVariableIndex() {int index = nextIndex.getAndIncrement();if (index < 0) {nextIndex.decrementAndGet();}return index;
}

5. ThreadLocalMap 的源码看过吗?

ThreadLocalMap 虽然被叫做 Map,其实它是没有实现 Map 接口的,但是结构还是和 HashMap 比较类似的,主要关注的是两个要素:元素数组散列方法

在这里插入图片描述

  • 元素数组

    一个 table 数组,存储 Entry 类型的元素,Entry 是 ThreaLocal 弱引用作为 key,Object 作为 value 的结构。

 private Entry[] table;
  • 散列方法

    散列方法就是怎么把对应的 key 映射到 table 数组的相应下标,ThreadLocalMap 用的是哈希取余法,取出 key 的 threadLocalHashCode,然后和 table 数组长度减一&运算(相当于取余)。

int i = key.threadLocalHashCode & (table.length - 1);

这里的 threadLocalHashCode 计算有点东西,每创建一个 ThreadLocal 对象,它就会新增0x61c88647,这个值很特殊,它是斐波那契数 也叫 黄金分割数hash增量为 这个数字,带来的好处就是 hash 分布非常均匀

    private static final int HASH_INCREMENT = 0x61c88647;private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);}

6. ThreadLocalMap 怎么解决 Hash 冲突的?

我们可能都知道 HashMap 使用了链表来解决冲突,也就是所谓的链地址法。

ThreadLocalMap 没有使用链表,自然也不是用链地址法来解决冲突了,它用的是另外一种方式——开放定址法。开放定址法是什么意思呢?简单来说,就是这个坑被人占了,那就接着去找空着的坑。

在这里插入图片描述

如上图所示,如果我们插入一个 value=27 的数据,通过 hash 计算后应该落入第 4 个槽位中,而槽位 4 已经有了 Entry 数据,而且 Entry 数据的 key 和当前不相等。此时就会线性向后查找,一直找到 Entry 为 null 的槽位才会停止查找,把元素放到空的槽中。

在 get 的时候,也会根据 ThreadLocal 对象的 hash 值,定位到 table 中的位置,然后判断该槽位 Entry 对象中的 key 是否和 get 的 key 一致,如果不一致,就判断下一个位置。

7. ThreadLocalMap 扩容机制了解吗?

在 ThreadLocalMap.set()方法的最后,如果执行完启发式清理工作后,未清理到任何数据,且当前散列数组中Entry的数量已经达到了列表的扩容阈值(len*2/3),就开始执行rehash()逻辑:

if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();

再着看 rehash()具体实现:这里会先去清理过期的 Entry,然后还要根据条件判断size >= threshold - threshold / 4 也就是size >= threshold* 3/4来决定是否需要扩容。

private void rehash() {//清理过期EntryexpungeStaleEntries();//扩容if (size >= threshold - threshold / 4)resize();
}//清理过期Entry
private void expungeStaleEntries() {Entry[] tab = table;int len = tab.length;for (int j = 0; j < len; j++) {Entry e = tab[j];if (e != null && e.get() == null)expungeStaleEntry(j);}
}

接着看看具体的resize()方法,扩容后的newTab的大小为老数组的两倍,然后遍历老的 table 数组,散列方法重新计算位置,开放地址解决冲突,然后放到新的newTab,遍历完成之后,oldTab中所有的entry数据都已经放入到newTab中了,然后 table 引用指向newTab

在这里插入图片描述

具体代码:

ThreadLocalMap resize

8. 父子线程怎么共享数据?

父线程能用 ThreadLocal 来给子线程传值吗?毫无疑问,不能。那该怎么办?

这时候可以用到另外一个类——InheritableThreadLocal

使用起来很简单,在主线程的 InheritableThreadLocal 实例设置值,在子线程中就可以拿到了。

public class InheritableThreadLocalTest {public static void main(String[] args) {final ThreadLocal threadLocal = new InheritableThreadLocal();// 主线程threadLocal.set("不擅技术");//子线程Thread t = new Thread() {@Overridepublic void run() {super.run();System.out.println("鄙人三某 ," + threadLocal.get());}};t.start();}
}

那原理是什么呢?

原理很简单,在 Thread 类里还有另外一个变量:

ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

在 Thread.init 的时候,如果父线程的inheritableThreadLocals不为空,就把它赋给当前线程(子线程)的inheritableThreadLocals

if (inheritThreadLocals && parent.inheritableThreadLocals != null)this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

相关文章:

Java并发编程面试题:ThreadLocal(8题)

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…...

Zabbix7.0安装(Ubuntu24.04+LNMP)

1.选择版本 下载Zabbix 2.安装虚拟机 这里选择在Ubuntu24.04上安装Zabbix. 安装链接https://blog.csdn.net/weixin_58189050/article/details/145446065 配置源 vim /etc/apt/sources.list deb https://mirrors.aliyun.com/ubuntu/ noble main restricted universe multive…...

从 0 到 1 构建数仓之DWD层

在企业数字化转型进程中&#xff0c;数据仓库的建设至关重要&#xff0c;而 DWD 层&#xff08;明细粒度事实层&#xff09;作为数据仓库的核心支撑层&#xff0c;其搭建质量直接影响企业数据的分析价值与决策效率。本文将结合实际案例与行业经验&#xff0c;详细阐述企业如何从…...

S4 HANA手工记账Tax Payable – FB41

本文主要介绍在S4 HANA OP中手工记账Tax Payable – FB41。具体请参照如下内容&#xff1a; 手工记账Tax Payable – FB41 该事务代码用于手工处理税码统驭科目的记账&#xff0c;一般税码科目需要设置为只能自动记账&#xff0c;因此无法手工对税码统驭科目记账&#xff0c;但…...

【自然语言处理(NLP)】NLP实战:IMDB影评情感分析项目

文章目录 介绍IMDB影评情感分析项目数据集项目实现1. 导包2. 加载IMDB数据3. 查看部分数据4. 分词5. 加载数据整合6. 构建模型7. 词嵌入8. 初始化模型和权重9. glove词向量10. 训练和评估11. 预测 个人主页&#xff1a;道友老李 欢迎加入社区&#xff1a;道友老李的学习社区 介…...

DIY Shell:探秘进程构建与命令解析的核心原理

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; Shell&#xff08;外壳&#xff09;是一个操作系统的用户界面&#xff0c;它提供了一种方式&#xff0c;使得用户能够与操作系统进行交互。Shell 是用户与操作系统之间的桥梁&#xff0c;允许用户通过命令行…...

通过Redisson构建延时队列并实现注解式消费

目录 一、序言二、延迟队列实现1、Redisson延时消息监听注解和消息体2、Redisson延时消息发布器3、Redisson延时消息监听处理器 三、测试用例四、结语 一、序言 两个月前接了一个4万的私活&#xff0c;做一个线上商城小程序&#xff0c;在交易过程中不可避免的一个问题就是用户…...

SQL Server配置管理器无法连接到 WMI 提供程序

目录 第一步第二部 第一步 发现没有资源管理器 ​​​​ 在文件夹找到管理器 打开发现报这个错误 配置管理器无法连接到 WMI 提供程序第二部 https://blog.csdn.net/thb369208315/article/details/126954074...

Linux内核源码:ext4 extent详解

在 Linux 系统的庞大体系中&#xff0c;文件系统就像是一个井然有序的图书馆&#xff0c;而 ext4 文件系统则是这座图书馆中极为重要的 “藏书室”&#xff0c;它负责高效管理和存储数据。在 ext4 众多的奥秘中&#xff0c;ext4 extent 犹如一颗璀璨的明珠&#xff0c;起着关键…...

Maven jar 包下载失败问题处理

Maven jar 包下载失败问题处理 1.配置好国内的Maven源2.重新下载3. 其他问题 1.配置好国内的Maven源 打开⾃⼰的 Idea 检测 Maven 的配置是否正确&#xff0c;正确的配置如下图所示&#xff1a; 检查项⼀共有两个&#xff1a; 确认右边的两个勾已经选中&#xff0c;如果没有请…...

自指学习:AGI的元认知突破

文章目录 引言:从模式识别到认知革命一、自指学习的理论框架1.1 自指系统的数学定义1.2 认知架构的三重反射1.3 与传统元学习的本质区别二、元认知突破的技术路径2.1 自指神经网络架构2.2 认知效能评价体系2.3 知识表示的革命三、实现突破的关键挑战3.1 认知闭环的稳定性3.2 计…...

排序算法--希尔排序

希尔排序是插入排序的改进版本&#xff0c;适合中等规模数据排序&#xff0c;性能优于简单插入排序。 // 希尔排序函数 void shellSort(int arr[], int n) {// 初始间隔&#xff08;gap&#xff09;为数组长度的一半&#xff0c;逐步缩小for (int gap n / 2; gap > 0; gap …...

Java 2024年面试总结(持续更新)

目录 最近趁着金三银四面了五六家公司吧&#xff0c;也整理了一些问题供大家参考一下&#xff08;适合经验三年左右的&#xff09;。 面试问题&#xff08;答案是我自己总结的&#xff0c;不一定正确&#xff09;&#xff1a; 总结&#xff1a; 最近趁着金三银四面了五六家公…...

TensorFlow是个啥玩意?

TensorFlow是一个开源的机器学习框架&#xff0c;由Google开发。它可以帮助开发者构建和训练各种机器学习模型&#xff0c;包括神经网络和深度学习模型。TensorFlow的设计理念是使用数据流图来表示计算过程&#xff0c;其中节点表示数学运算&#xff0c;边表示数据流动。 Tens…...

不可信的搜索路径(CWE-426)

漏洞描述&#xff1a;程序使用关键资源时&#xff08;如动态链接库、执行文件、配置文件等&#xff09;没有明确的指定资源的路径&#xff0c;而是依赖操作系统去搜索资源&#xff0c;这种行为可能被攻击者利用&#xff0c;通过在搜索优先级较高的目录放置不良资源&#xff0c;…...

Linux——基础命令

$&#xff1a;普通用户 #&#xff1a;超级用户 cd 切换目录 cd 目录 &#xff08;进入目录&#xff09; cd ../ &#xff08;返回上一级目录&#xff09; cd ~ &#xff08;切换到当前用户的家目录&#xff09; cd - &#xff08;返回上次目录&#xff09; pwd 输出当前目…...

利用TensorFlow.js实现浏览器端机器学习:一个全面指南

引言 随着深度学习技术的不断发展&#xff0c;机器学习已从传统的服务器端运算逐渐转向了前端技术。TensorFlow.js 是 Google 推出的一个用于在浏览器中进行机器学习的开源库&#xff0c;它允许开发者在浏览器中直接运行机器学习模型&#xff0c;而无需依赖后端服务器。Tensor…...

利用HTML和css技术编写学校官网页面

目录 一&#xff0c;图例展示 二&#xff0c;代码说明 1&#xff0c;html部分&#xff1a; 【第一张图片】 【第二张图片】 【第三张图片】 2&#xff0c;css部分&#xff1a; 【第一张图片】 【第二张图片】 【第三张图片】 三&#xff0c;程序代码 一&#xff0c;…...

SpringSecurity密码编码器:使用BCrypt算法加密、自定义密码编码器

1、Spring Security 密码编码器 Spring Security 作为一个功能完备的安全性框架,一方面提供用于完成加密操作的 PasswordEncoder 组件,另一方面提供一个可以在应用程序中独立使用的密码模块。 1.1 PasswordEncoder 抽象接口 在 Spring Security 中,PasswordEncoder 接口代…...

笔记:新能源汽车零部件功率级测试怎么进行?

摘要:本文旨在梳理主机厂对新能源汽车核心零部件功率级测试需求,通过试验室的主流设备仪器集成,快速实现试验方案搭建,并体现测试测量方案的时效性、便捷性优势。目标是通过提升实现设备的有效集成能力、实现多设备测试过程的有效协同、流程化测试,可快速采集、分析当前数…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

React19源码系列之 事件插件系统

事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”

目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...