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

FastThreadLocal 快在哪里 ?

FastThreadLocal 快在哪里 ?

  • 引言
  • FastThreadLocal
    • set
      • 如何获取当前线程私有的InternalThreadLocalMap ?
      • 如何知道当前线程使用到了哪些FastThreadLocal实例 ?
    • get
    • 垃圾回收
  • 小结


引言

FastThreadLocal 是 Netty 中造的一个轮子,那么为什么放着好端端的ThreadLocal不用,却要重复造轮子呢?下面是Netty官方在源码注释中给出的解释:

  • FastThreadLocal是ThreadLocal的一种特殊变体,当从FastThreadLocalThread访问时可以获得更高的访问性能。
  • 内部FastThreadLocal使用数组中的常量索引来查找变量,而不是使用哈希码和哈希表来查找。尽管看似非常微小,但与使用哈希表相比,它在性能上略有优势,特别是在频繁访问时。

本文我们就来简单看看FastThreadLocal的具体实现。

在正式进入实现解析之前,下面先给出FastThreadLocal使用示例:

    private static void fastThreadLocal() {final int MAX = 100000;long start = System.currentTimeMillis();// DefaultThreadFactory是Netty提供的实现,用于创建类型为FastThreadLocalThread的线程DefaultThreadFactory defaultThreadFactory = new DefaultThreadFactory(FastThreadLocalTest.class);FastThreadLocal<String>[] fastThreadLocal = new FastThreadLocal[MAX];for (int i = 0; i < MAX; i++) {fastThreadLocal[i] = new FastThreadLocal<>();}// 测试单线程读写FastThreadLocal的耗时Thread thread = defaultThreadFactory.newThread(() -> {for (int i = 0; i < MAX; i++) {fastThreadLocal[i].set("java: " + i);}System.out.println("fastThreadLocal set: " + (System.currentTimeMillis() - start));for (int i = 0; i < MAX; i++) {for (int j = 0; j < MAX; j++) {fastThreadLocal[i].get();}}});thread.start();try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("fastThreadLocal total: " + (System.currentTimeMillis() - start));}

FastThreadLocal

在这里插入图片描述
整体来看,FastThreadLocal的整体结构和ThreadLocal是一致的,唯一的区别在于InternalThreadLocalMap 内部存储上,ThreadLocalMap 采用哈希定位实现,而InternalThreadLocalMap 采用数组常量索引实现,即:

  • 每个FastThreadLocal与一个固定的数字常量相关联。

在这里插入图片描述
FastThreadLocal内部都会保存一个index下标,该下标在FastThreadLocal实例初始化的时候被赋值:

public class FastThreadLocal<V> {// index 被final修饰,确保FastThreadLocal在InternalThreadLocalMap数组中的下标是固定不变的private final int index;public FastThreadLocal() {// 计数器不断递增index = InternalThreadLocalMap.nextVariableIndex();}...
}    

还有一点也很重要,InternalThreadLocalMap内部使用的桶数组没有采用弱引用实现,而是普通的强引用:

    // 1. InternalThreadLocalMap中桶数组的实现private Object[] indexedVariables;// 2. ThreadLocalMap中桶数组的实现static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}private Entry[] table;

大家可以思考,InternalThreadLocalMap此处不使用弱引用实现,是否存在内存泄漏问题 ? 即当用户程序本身失去了对FastThreadLocal实例的强引用后,仍然被InternalThreadLocalMap强引用的FastThreadLocal如何被回收掉呢?

这里需要注意一点: InternalThreadLocalMap与ThreadLocalMap没有继承关系
在这里插入图片描述


set

当我们通过FastThreadLocal的set方法设置值时,其实和ThreadLocal一样,还是向InternalThreadLocalMap中设置值:

    public final void set(V value) {// 1. UNSET 是空桶标记-->等价于ThreadLocal中被垃圾回收后key为null的空Entry if (value != InternalThreadLocalMap.UNSET) {// 2. 获取与当前线程关联的InternalThreadLocalMap// 以FastThreadLocal为key,value为val设置到InternalThreadLocalMap中    InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();setKnownNotUnset(threadLocalMap, value);} else {// 3. 当设置的值为UNSET时,表明需要清空当前FastThreadLocalremove();}}

关于Set的整个流程,有两点值得我们思考:

如何获取当前线程私有的InternalThreadLocalMap ?

如果我们当前使用的线程类型为FastThreadLocalThread,那么可以直接获取FastThreadLocalThread内部持有的InternalThreadLocalMap:

public class FastThreadLocalThread extends Thread {...// 这一点和Thread内部保存ThreadLocalMap实现一致private InternalThreadLocalMap threadLocalMap;...
}

如果我们当前使用的线程类型是原始类型Thread,那么Netty这里会将InternalThreadLocalMap保存于当前线程私有的ThreadLocal内部:

public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {private static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap =new ThreadLocal<InternalThreadLocalMap>();...
}            

上面两种获取方式,前一种被称为fastGet,而后一种被称为slowGet :

public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {public static InternalThreadLocalMap get() {Thread thread = Thread.currentThread();if (thread instanceof FastThreadLocalThread) {return fastGet((FastThreadLocalThread) thread);} else {return slowGet();}}// 1. 当前线程类型为FastThreadLocalThread,则直接从获取其内部持有的InternalThreadLocalMap实例private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();if (threadLocalMap == null) {thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());}return threadLocalMap;}// 2. 当前线程类型为传统的Thread类型,则从当前线程私有的ThreadLocal中获取InternalThreadLocalMap实例 private static InternalThreadLocalMap slowGet() {InternalThreadLocalMap ret = slowThreadLocalMap.get();if (ret == null) {ret = new InternalThreadLocalMap();slowThreadLocalMap.set(ret);}return ret;}  ...
}  

如何知道当前线程使用到了哪些FastThreadLocal实例 ?

为什么FastThreadLocal需要获取到当前线程使用到的所有FastThreadLocal实例呢?

上面说过,InternalThreadLocalMap本身没有采用弱引用实现,那么Netty就需要另想办法回收掉失去了用户程序强引用的FastThreadLocal,防止产生内存泄漏。Netty此处采用的方式就是在FastThreadLocalRunnable包装的Runnable对象任务执行完毕后,清理掉当前线程使用到的所有FastThreadLocal实现的:

final class FastThreadLocalRunnable implements Runnable {private final Runnable runnable;private FastThreadLocalRunnable(Runnable runnable) {this.runnable = ObjectUtil.checkNotNull(runnable, "runnable");}@Overridepublic void run() {try {runnable.run();} finally {FastThreadLocal.removeAll();}}static Runnable wrap(Runnable runnable) {return runnable instanceof FastThreadLocalRunnable ? runnable : new FastThreadLocalRunnable(runnable);}
}

那这里还是回归第二个问题本身,即如何获取当前线程使用到的所有FastThreadLocal实例呢?

public class FastThreadLocal<V> {private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {// 1. 尝试向threadLocalMap中设置值,如果是第一次设置,则记录当前线程使用到了当前ThreadLocal// (直接常量值定位FastThreadLocal在ThreadLocalMap的哪个槽中) if (threadLocalMap.setIndexedVariable(index, value)) {// 2. 记录当前线程使用到了当前FastThreadLocaladdToVariablesToRemove(threadLocalMap, this);}}private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {// 1. variablesToRemoveIndex固定为0,threadLocalMap数组第一个槽位存放当前线程使用到的FastThreadLocal集合Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);Set<FastThreadLocal<?>> variablesToRemove;// 2. 说明当前FastThreadLocal是当前线程第一个使用到的FastThreadLocal实例if (v == InternalThreadLocalMap.UNSET || v == null) {// 3. 准备一个Set集合variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());// 4. threadLocalMap中的0号槽位固定存放当前线程使用到的FastThreadLocal实例threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);} else {variablesToRemove = (Set<FastThreadLocal<?>>) v;}// 5. 记录当前FastThreadLocal到集合中去variablesToRemove.add(variable);}...
}public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {public boolean setIndexedVariable(int index, Object value) {Object[] lookup = indexedVariables;// 1. 判断InternalThreadLocalMap是否装满if (index < lookup.length) {Object oldValue = lookup[index];lookup[index] = value;// 2. 如果当前槽位先前为空,说明是第一次使用到当前FastThreadLocalreturn oldValue == UNSET;} else {// 3. 执行扩容,扩容完毕后,在设置进去 --> 说明当前FastThreadLocal是第一次被使用expandIndexedVariableTableAndSet(index, value);return true;}}....
}    

当前线程会在第一次使用到某个FastThreadLocal时进行记录,使用到的FastThreadLocal集合保存在InternalThreadLocalMap数组的0号槽位中:

public class FastThreadLocal<V> {// 当FastThreadLocal类本身执行初始化时,该下标就被初始化了,值默认为0private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();...
}public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {// 这里的计数器也是全局共享的private static final AtomicInteger nextIndex = new AtomicInteger();...public static int nextVariableIndex() { // 每次获取下标时,计数器累加一位int index = nextIndex.getAndIncrement();...return index;}
}    

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

set的整个流程中,我们也可以看出FastThreadLocal快就快在,可以根据当前FastThreadLocal实例关联的常量值直接定位其在InternalThreadLocalMap中的位置。


get

FastThreadLocal get的流程很简单,如下所示:

public class FastThreadLocal<V> {public final V get(InternalThreadLocalMap threadLocalMap) {// 1. 直接常量定位所在槽位Object v = threadLocalMap.indexedVariable(index);// 2. 如果当前FastThreadLocal并非首次访问,则直接对应的值if (v != InternalThreadLocalMap.UNSET) {return (V) v;}// 3. 初始化FastThreadLocalreturn initialize(threadLocalMap);}private V initialize(InternalThreadLocalMap threadLocalMap) {V v = null;try {// 1. 调用回调进行初始化v = initialValue();} catch (Exception e) {PlatformDependent.throwException(e);}// 2. 设置初始化的值threadLocalMap.setIndexedVariable(index, v);// 3. 注册当前FastThreadLocal,即记录当前线程使用了当前FastThreadLocal实例addToVariablesToRemove(threadLocalMap, this);return v;}...
}    

垃圾回收

上面说过,InternalThreadLocalMap本身没有采用弱引用实现,那么Netty就需要另想办法回收掉失去了用户程序强引用的FastThreadLocal,防止产生内存泄漏。Netty此处采用的方式就是在FastThreadLocalRunnable包装的Runnable对象任务执行完毕后,清理掉当前线程使用到的所有FastThreadLocal实现的,这一点上面已经提到过了,下面我们看看具体实现。

final class FastThreadLocalRunnable implements Runnable {private final Runnable runnable;private FastThreadLocalRunnable(Runnable runnable) {this.runnable = ObjectUtil.checkNotNull(runnable, "runnable");}@Overridepublic void run() {try {runnable.run();} finally {FastThreadLocal.removeAll();}}static Runnable wrap(Runnable runnable) {return runnable instanceof FastThreadLocalRunnable ? runnable : new FastThreadLocalRunnable(runnable);}
}

FastThreadLocal提供了一个静态的removeAll方法,用于清除当前线程使用到的所有FastThreadLocal实例:

public class FastThreadLocal<V> {... public static void removeAll() {// 1. 如果当前线程没有使用到FastThreadLocal,这里直接返回InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();if (threadLocalMap == null) {return;}try {// 2. 获取固定的0号槽位保存的Set集合,该集合内保存了当前线程使用到的所有FastThreadLocal实例集合 Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);if (v != null && v != InternalThreadLocalMap.UNSET) {Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;// 3. 遍历该集合内每个FastThreadLocal实例,依次调用remove方法 FastThreadLocal<?>[] variablesToRemoveArray =variablesToRemove.toArray(new FastThreadLocal[0]);for (FastThreadLocal<?> tlv: variablesToRemoveArray) {tlv.remove(threadLocalMap);}}} finally {// 4. 置空threadlocalmapInternalThreadLocalMap.remove();}}
  1. 清空单个FastThreadLocal
public class FastThreadLocal<V> {public final void remove(InternalThreadLocalMap threadLocalMap) {if (threadLocalMap == null) {return;}// 1. 清除当前FastThreadLocal占用的槽位Object v = threadLocalMap.removeIndexedVariable(index);// 2. 取消当前FastThreadLocal的注册removeFromVariablesToRemove(threadLocalMap, this);// 3. 执行回调通知  if (v != InternalThreadLocalMap.UNSET) {try {onRemoval((V) v);} catch (Exception e) {PlatformDependent.throwException(e);}}}private static void removeFromVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {// 1. 获取threadlocalmap的0号槽位保存的set集合  Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);...// 2. 从set集合中移除当前fastThreadLocalSet<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;variablesToRemove.remove(variable);}...
}public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {public Object removeIndexedVariable(int index) {Object[] lookup = indexedVariables;if (index < lookup.length) {Object v = lookup[index];// 将对应槽位设置为UNSETlookup[index] = UNSET;return v;} else {return UNSET;}}...
}
  1. 置空ThreadLocalMap
public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {public static void remove() {Thread thread = Thread.currentThread();// 1. 如果threadLocalMap保存在FastThreadLocalThread内部,则直接设置为nullif (thread instanceof FastThreadLocalThread) {((FastThreadLocalThread) thread).setThreadLocalMap(null);} else {// 2. 如果保存在当前线程threadlocal中,则调用threadlocal的remove方法移除 slowThreadLocalMap.remove();}}...
} 

小结

FastThreadLocal为什么那么快,这个问题比较好回答:

  1. FastThreadLocal 内部维护了一个索引常量 index,该常量在每次创建 FastThreadLocal 中都会自动+1,从而保证了下标的不重复性。
  2. 这要做虽然会产生大量的 index,但避免了在 ThreadLocal 中计算索引下标位置以及处理 hash 冲突带来的损耗,所以在操作数组时使用固定下标要比使用计算哈希下标有一定的性能优势,特别是在频繁使用时会非常显著,用空间换时间,这就是高性能 Netty 的巧妙之处。
  3. 要利用 FastThreadLocal 带来的性能优势,就必须结合使用 FastThreadLocalThread 线程类或其子类,因为 FastThreadLocalThread 线程类会存储必要的状态,如果使用了非 FastThreadLocalThread 线程类则会回到常规 ThreadLocal。

下面给出一个测试用例,来看看FastThreadLocal和ThreadLocal在性能上的差异:

public class FastThreadLocalTest {public static void main(String[] args) {new Thread(FastThreadLocalTest::threadLocal).start();new Thread(FastThreadLocalTest::fastThreadLocal).start();}private static void fastThreadLocal() {final int MAX = 100000;long start = System.currentTimeMillis();// DefaultThreadFactory是Netty提供的实现,用于创建类型为FastThreadLocalThread的线程DefaultThreadFactory defaultThreadFactory = new DefaultThreadFactory(FastThreadLocalTest.class);FastThreadLocal<String>[] fastThreadLocal = new FastThreadLocal[MAX];for (int i = 0; i < MAX; i++) {fastThreadLocal[i] = new FastThreadLocal<>();}// 测试单线程读写FastThreadLocal的耗时Thread thread = defaultThreadFactory.newThread(() -> {for (int i = 0; i < MAX; i++) {fastThreadLocal[i].set("java: " + i);}System.out.println("fastThreadLocal set: " + (System.currentTimeMillis() - start));for (int i = 0; i < MAX; i++) {for (int j = 0; j < MAX; j++) {fastThreadLocal[i].get();}}});thread.start();try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("fastThreadLocal total: " + (System.currentTimeMillis() - start));}private static void threadLocal() {final int MAX = 100000;long start = System.currentTimeMillis();ThreadLocal<String>[] threadLocals = new ThreadLocal[MAX];for (int i = 0; i < MAX; i++) {threadLocals[i] = new ThreadLocal<>();}Thread thread = new Thread(() -> {for (int i = 0; i < MAX; i++) {threadLocals[i].set("java: " + i);}System.out.println("threadLocal set: " + (System.currentTimeMillis() - start));for (int i = 0; i < MAX; i++) {for (int j = 0; j < MAX; j++) {threadLocals[i].get();}}});thread.start();try {thread.join();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("threadLocal total: " + (System.currentTimeMillis() - start));}}

在这里插入图片描述
在大量读写面前,写操作的效率差不多,但读操作 FastThreadLocal 比 ThreadLocal 快的不是一个数量级,简直是秒杀 ThreadLocal 的存在。

当我们把max的值缩小为1000时,此时读写操作不多时,ThreadLocal 明显更胜一筹!
在这里插入图片描述
Netty 中的 FastThreadLocal 在大量频繁读写操作时效率要高于 ThreadLocal,但要注意结合 Netty 自带的线程类使用。

如果没有大量频繁读写操作的场景,JDK 自带的 ThreadLocal 足矣,并且性能还要优于 FastThreadLocal。

相关文章:

FastThreadLocal 快在哪里 ?

FastThreadLocal 快在哪里 &#xff1f; 引言FastThreadLocalset如何获取当前线程私有的InternalThreadLocalMap &#xff1f;如何知道当前线程使用到了哪些FastThreadLocal实例 ? get垃圾回收 小结 引言 FastThreadLocal 是 Netty 中造的一个轮子&#xff0c;那么为什么放着…...

ggkegg | 用这个神包玩转kegg数据库吧!~(一)

1写在前面 好久没更了&#xff0c;实在是太忙了&#xff0c;值班真的是根本不不睡觉啊&#xff0c;一忙一整天&#xff0c;忙到怀疑人生。&#x1f62d; 最近看到比较&#x1f525;的就是ggkegg包&#xff0c;感觉使用起来还是有一定难度的。&#x1fae0; 和大家分享一下使用教…...

【小黑送书—第三期】>>《深入浅出SSD》

近年来国家大力支持半导体行业&#xff0c;鼓励自主创新&#xff0c;中国SSD技术和产业良性发展&#xff0c;产业链在不断完善&#xff0c;与国际厂商的差距逐渐缩小。但从行业发展趋势来看&#xff0c;SSD相关技术仍有大幅进步的空间&#xff0c;SSD相关技术也确实在不断前进。…...

linux虚拟机查看防火墙状态

linux虚拟机查看防火墙状态 在Linux虚拟机中&#xff0c;你可以通过以下几种方法查看防火墙状态&#xff1a; 查看iptables防火墙状态 对于使用iptables防火墙的Linux系统&#xff0c;可以使用以下命令查看防火墙状态&#xff1a; sudo iptables -L -v -n查看firewalld防火墙…...

Docker 安装 MongoDB

一、什么是MongoDB MongoDB 是一个基于分布式文件存储的数据库。是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。 二、MongoDB的安装 这里使用docker来安装MongoD 1.docker 拉取mysql镜像 docker pu…...

c++解压压缩包文件

功能实现需要依赖相关头文件和库文件&#xff0c;我这里的是64位的。需要的可以在这下载&#xff1a;https://download.csdn.net/download/bangtanhui/88403596 参考代码如下&#xff1a; #include <zip.h> #pragma comment(lib,"libzip.lib")//解压压缩包 /…...

MySql学习笔记:MySql性能优化

本文是自己的学习笔记&#xff0c;主要参考以下资料 - 大话设计模式&#xff0c;程杰著&#xff0c;清华大学出版社出版 - 马士兵教育 1、MySql调优金字塔2、MySql调优2.1、查询性能2.1.1、慢查询2.1.1.1、总结 1、MySql调优金字塔 Mysql 调优时设计三个层面&#xff0c;分别是…...

机器学习(四十八):粒子群优化(PSO)-提升机器学习模型准确率的秘密武器

文章目录 PSO算法简介为什么使用PSO优化机器学习参数?PSO与其他启发式算法的比较如何使用PSO优化机器学习模型?模块安装和测试例子PSO优化决策树总结PSO算法简介 粒子群优化算法(Particle Swarm Optimization,PSO)是一种模拟鸟群觅食行为的启发式算法。在PSO算法中,每个…...

MySQL - mysql服务基本操作以及基本SQL语句与函数

文章目录 操作mysql客户端与 mysql 服务之间的小九九了解 mysql 基本 SQL 语句语法书写规范SQL分类DDL库表查增 mysql数据类型数值类型字符类型日期类型 示例修改&#xff08;表操作&#xff09; DML添加数据删除数据修改数据 DQL查询多个字段条件查询聚合函数分组查询排序查询…...

[图论]哈尔滨工业大学(哈工大 HIT)学习笔记16-22

视频来源&#xff1a;2.7.1 补图_哔哩哔哩_bilibili 目录 1. 补图 1.1. 补图 2. 双图 2.1. 双图定理 3. 图兰定理/托兰定理 4. 极图理论 5. 欧拉图 5.1. 欧拉迹 5.2. 欧拉闭迹 5.3. 欧拉图 5.4. 欧拉定理 5.5. 伪图 1. 补图 1.1. 补图 &#xff08;1&#xff09;…...

使用关键字abstract 声明抽象类-PHP8知识详解

抽象类只能作为父类使用&#xff0c;因为抽象类不能被实例化。抽象类使用关键字abstract 声明&#xff0c;具体的使用语法格式如下&#xff1a; abstract class 抽象类名称{ //抽象类的成员变量列表 abstract function 成员方法1(参数); //抽象类的成员方法 abstract functi…...

Java中使用正则表达式

正则表达式 正则表达式&#xff08;Regular Expression&#xff09;是一种用于匹配、查找和替换文本的强大工具。它由一系列字符和特殊字符组成&#xff0c;可以用来描述字符串的模式。在编程和文本处理中&#xff0c;正则表达式常被用于验证输入、提取信息、搜索和替换文本等…...

Python之字符串分割替换移除

Python之字符串分割替换移除 分割 split(sepNone, maxsplit-1) -> list of strings 从左至右sep 指定分割字符串&#xff0c;缺省的情况下空白字符串作为分隔符maxsplit 指定分割的次数&#xff0c;-1 表示遍历整个字符串立即返回列表 rsplit(sepNone, maxsplit-1) -> …...

ubuntu增加内存

文章目录 1、硬盘操作步骤第二步:点击【扩展】(必须关闭ubuntu电源才能修改)第三步:修改【最大磁盘容量大小】1、硬盘操作步骤 最近发现Ubuntu空间不足,怎么去扩容呢? 第一步:点击【硬盘】 第二步:点击【扩展】(必须关闭ubuntu电源才能修改) 第三步:修改【最大磁…...

黑客都是土豪吗?真实情况是什么?

黑客的利益链条真的这么大这么好么,连最外围的都可以靠信息不对称赚普通人大学毕业上班族想都不敢想的金钱数目,黑客们是不是基本都是土豪 网络技术可以称为黑客程度的技术是不是真的很吃香&#xff1f;如果大部分大学生的智力资源都用在学习网络技术&#xff0c;会不会出现僧…...

企业想过等保,其中2FA双因素认证手段必不可少

随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显。等保2.0时代的到来&#xff0c;意味着企业和组织需要更加严格地保护自身的信息安全。而在这个过程中&#xff0c;双因素认证的重要性逐渐得到广泛认可。本文将探讨 2FA 双因素认证的重要性。 在了解 2FA 双因素认证的…...

Combination Lock

题目描述 新学期开学&#xff0c;您又回到了学校。您需要记住如何操作储物柜上的组合锁。一个组合锁的常见设计如图 1 所示。组合锁有一个圆形刻度表盘&#xff0c;在表盘上&#xff0c;有 40 个编号为从 0 至 39 的刻度&#xff0c;正上方有一个刻度指针。一个组合由这些数字…...

SpringBoot解决LocalDateTime返回数据为数组问题

现象&#xff1a; 在SpringBoot项目中&#xff0c;接口返回的数据出现LocalDateTime对象被转换成了数组 原因分析&#xff1a; 默认序列化情况下会使用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS。使用这个解析时就会打印出数组。 解决方法&#xff1a; 在配置类中…...

【数字人】2、MODA | 基于人脸关键点的语音驱动单张图数字人生成(ICCV2023)

文章目录 一、背景二、方法2.1 问题描述和数据预处理2.2 Mapping-Once network with Dual Attentions2.3 Facial Composer Network2.4 使用 TPE 来合成人像图片 三、效果3.1 训练细节3.2 数据3.3 测评指标3.4 结果比较 四、代码4.1 数据前处理4.2 训练4.3 推理 论文&#xff1a…...

群狼调研(长沙物业第三方评优)开展房地产市场调查内容设计

湖南房地产市场近年来表现出多元化的发展趋势。为了在竞争激烈的市场中获得更好的发展&#xff0c;房地产企业需要密切关注市场变化&#xff0c;合理规划开发项目&#xff0c;同时提高产品质量和服务水平&#xff0c;以满足消费者的需求和期望。群狼调研(长沙神秘顾客调查)在房…...

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 如果用户登录尝试失败次…...

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

汇编常见指令

汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX&#xff08;不访问内存&#xff09;XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

解读《网络安全法》最新修订,把握网络安全新趋势

《网络安全法》自2017年施行以来&#xff0c;在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂&#xff0c;网络攻击、数据泄露等事件频发&#xff0c;现行法律已难以完全适应新的风险挑战。 2025年3月28日&#xff0c;国家网信办会同相关部门起草了《网络安全…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...