Java高性能并发利器-VarHandle
1. 什么是 VarHandle?
VarHandle 是 Java 9 引入的类,用于对变量(对象字段、数组元素、静态变量等)进行低级别、高性能的原子操作(如 CAS、原子读写)。它是 java.util.concurrent.atomic 和 sun.misc.Unsafe 的安全替代品,提供类型安全和规范化的内存顺序控制。
2. 获取 VarHandle 的 4 种方式
(1) 实例字段
class MyClass {private int value;// 创建 VarHandlestatic final VarHandle VALUE_HANDLE;static {try {VALUE_HANDLE = MethodHandles.privateLookupIn(MyClass.class, MethodHandles.lookup()).findVarHandle(MyClass.class, "value", int.class);} catch (Exception e) {throw new Error(e);}}
}
(2) 静态字段
class MyClass {static int staticValue;static final VarHandle STATIC_HANDLE;static {try {STATIC_HANDLE = MethodHandles.lookup().findStaticVarHandle(MyClass.class, "staticValue", int.class);} catch (Exception e) {throw new Error(e);}}
}
(3) 数组元素
int[] array = new int[10];
VarHandle arrayHandle = MethodHandles.arrayElementVarHandle(int[].class);// 操作数组元素
arrayHandle.set(array, 5, 100); // array[5] = 100
(4) 堆外内存
// 通过 ByteBuffer 的 VarHandle 访问堆外内存
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
VarHandle bufferHandle = buffer.varHandle(int.class, 0);
bufferHandle.set(buffer.position(0), 123);
3. 内存顺序(Memory Order)详解
VarHandle 允许通过 AccessMode 控制内存操作顺序,解决指令重排序和可见性问题:
| 内存模式 | 描述 |
|---|---|
| Plain(普通) | 无任何内存屏障,可能被重排序(类似普通变量读写) |
| Opaque(不透明) | 保证线程间的原子性,但不保证全局内存顺序(JDK 9+) |
| Release/Acquire | 写操作(Release)对其他线程的读操作(Acquire)可见 |
| Volatile(易变) | 完全按顺序执行,类似 volatile 关键字 |
示例:设置内存模式
// 以 volatile 模式读写
int value = (int) VALUE_HANDLE.getVolatile(myObject);
VALUE_HANDLE.setVolatile(myObject, newValue);// 以 Release/Acquire 模式操作
VALUE_HANDLE.setRelease(myObject, newValue); // 写操作对其他线程可见
int v = (int) VALUE_HANDLE.getAcquire(myObject); // 确保读到最新值
4. 核心原子操作
(1) CAS(Compare-And-Swap)
boolean success = VALUE_HANDLE.compareAndSet(myObject, expectedValue, newValue);
(2) 原子递增/递减
int oldValue = (int) VALUE_HANDLE.getAndAdd(myObject, 1); // 类似 i++
(3) 原子更新
int updated = (int) VALUE_HANDLE.getAndUpdate(myObject, v -> v * 2);
(4) 原子读取-修改-写入
int result = (int) VALUE_HANDLE.getAndBitwiseOr(myObject, 0b100); // 位操作
5. 高级用法示例
示例 1:实现无锁栈(Lock-Free Stack)
class LockFreeStack<T> {private static class Node<T> {T value;Node<T> next;}private volatile Node<T> top;private static final VarHandle TOP_HANDLE;static {try {TOP_HANDLE = MethodHandles.lookup().findVarHandle(LockFreeStack.class, "top", Node.class);} catch (Exception e) {throw new Error(e);}}public void push(T value) {Node<T> newNode = new Node<>();newNode.value = value;Node<T> oldTop;do {oldTop = top;newNode.next = oldTop;} while (!TOP_HANDLE.compareAndSet(this, oldTop, newNode));}public T pop() {Node<T> oldTop;Node<T> newTop;do {oldTop = top;if (oldTop == null) return null;newTop = oldTop.next;} while (!TOP_HANDLE.compareAndSet(this, oldTop, newTop));return oldTop.value;}
}
示例 2:高性能计数器
class Counter {private int count;private static final VarHandle COUNT_HANDLE;static {try {COUNT_HANDLE = MethodHandles.lookup().findVarHandle(Counter.class, "count", int.class);} catch (Exception e) {throw new Error(e);}}// 原子递增(比 AtomicInteger 更轻量)public int increment() {return (int) COUNT_HANDLE.getAndAdd(this, 1);}
}
6. 与 Unsafe 的对比
| 特性 | VarHandle | Unsafe |
|---|---|---|
| 类型安全 | ✔️ 强类型检查 | ❌ 依赖偏移量和手动类型转换 |
| 内存顺序控制 | ✔️ 提供明确语义 | ❌ 需要开发者自行管理屏障 |
| 兼容性 | ✔️ 标准 API,长期支持 | ❌ 内部 API,可能被移除 |
| 访问权限 | ✔️ 受 MethodHandles.Lookup 限制 | ❌ 可绕过 Java 访问控制 |
7. 性能优化建议
- 优先使用
volatile模式:在需要全局可见性时使用getVolatile/setVolatile。 - 避免反射开销:将
VarHandle定义为static final常量。 - 减少 CAS 竞争:在高并发场景中,使用
VarHandle配合回退策略(如指数退避)。
8. 常见问题
Q1:VarHandle 能否替代 AtomicInteger?
是的!AtomicInteger 内部已用 VarHandle 实现(JDK 9+),但直接使用 VarHandle 可以避免包装类的开销。
Q2:如何处理私有字段?
使用 MethodHandles.privateLookupIn() 获取访问权限:
VarHandle handle = MethodHandles.privateLookupIn(MyClass.class, MethodHandles.lookup()).findVarHandle(MyClass.class, "privateField", int.class);
Q3:VarHandle 支持哪些数据类型?
- 基本类型:
int,long,double, 等 - 对象引用:
Object - 数组:任意类型的数组元素
9. 总结
VarHandle 是 Java 并发编程的利器,适用于:
- 实现高性能无锁数据结构
- 替代
AtomicXXX类减少开销 - 直接操作堆外内存或数组
10. 场景
场景 1:高性能环形缓冲区(无锁队列)
需求:实现多生产者-多消费者的环形缓冲区,避免锁竞争。
核心:利用 VarHandle 的 getAndAdd 和 compareAndSet 实现无锁指针推进。
public class RingBuffer<T> {private final Object[] buffer;private final int capacity;private volatile long head; // 消费者指针private volatile long tail; // 生产者指针private static final VarHandle HEAD_HANDLE;private static final VarHandle TAIL_HANDLE;private static final VarHandle BUFFER_HANDLE;static {try {MethodHandles.Lookup lookup = MethodHandles.lookup();HEAD_HANDLE = lookup.findVarHandle(RingBuffer.class, "head", long.class);TAIL_HANDLE = lookup.findVarHandle(RingBuffer.class, "tail", long.class);BUFFER_HANDLE = MethodHandles.arrayElementVarHandle(Object[].class);} catch (Exception e) {throw new Error(e);}}public RingBuffer(int capacity) {this.capacity = capacity;this.buffer = new Object[capacity];}// 生产者写入(多线程安全)public boolean offer(T item) {long currentTail;long newTail;do {currentTail = (long) TAIL_HANDLE.getVolatile(this);newTail = currentTail + 1;if (newTail - head >= capacity) return false; // 队列已满} while (!TAIL_HANDLE.compareAndSet(this, currentTail, newTail));// 写入数据(使用 Release 模式保证可见性)BUFFER_HANDLE.setRelease(buffer, (int) (currentTail % capacity), item);return true;}// 消费者读取(多线程安全)public T poll() {long currentHead;long newHead;do {currentHead = (long) HEAD_HANDLE.getVolatile(this);if (currentHead >= tail) return null; // 队列为空newHead = currentHead + 1;} while (!HEAD_HANDLE.compareAndSet(this, currentHead, newHead));// 读取数据(Acquire 模式确保读取到最新值)return (T) BUFFER_HANDLE.getAcquire(buffer, (int) (currentHead % capacity));}
}
场景 2:线程安全的延迟初始化(替代双重检查锁)
需求:实现线程安全的单例,避免 synchronized 开销。
核心:用 VarHandle 的 compareAndExchange 替代双重检查锁,性能更高。
public class LazyInitializer {private volatile Resource resource;private static final VarHandle RESOURCE_HANDLE;static {try {RESOURCE_HANDLE = MethodHandles.lookup().findVarHandle(LazyInitializer.class, "resource", Resource.class);} catch (Exception e) {throw new Error(e);}}public Resource getResource() {Resource res = resource;if (res == null) {Resource newRes = createResource();// 原子替换:若当前值为 null,则替换为 newResres = (Resource) RESOURCE_HANDLE.compareAndExchange(this, null, newRes);if (res == null) {res = newRes;}}return res;}private Resource createResource() {return new Resource(); // 初始化逻辑}
}
场景 3:自定义原子浮点操作
需求:Java 原生的 Atomic 类不支持 float,用 VarHandle 实现原子浮点更新。
核心:通过 Float.floatToIntBits 和 VarHandle 的 getAndBitwiseXor 模拟原子操作。
public class AtomicFloat {private volatile int bits; // 用 int 存储 float 的二进制形式private static final VarHandle BITS_HANDLE;static {try BITS_HANDLE = MethodHandles.lookup().findVarHandle(AtomicFloat.class, "bits", int.class);} catch (Exception e) {throw new Error(e);}}public float get() {return Float.intBitsToFloat((int) BITS_HANDLE.getVolatile(this));}public void set(float value) {BITS_HANDLE.setVolatile(this, Float.floatToIntBits(value));}// 原子加法(通过CAS实现)public float addAndGet(float delta) {int prevBits, newBits;do {prevBits = (int) BITS_HANDLE.getVolatile(this);float prevValue = Float.intBitsToFloat(prevBits);float newValue = prevValue + delta;newBits = Float.floatToIntBits(newValue);} while (!BITS_HANDLE.compareAndSet(this, prevBits, newBits));return Float.intBitsToFloat(newBits);}
}
场景 4:状态机的高效切换
需求:多线程环境下安全切换状态,支持从 INIT → RUNNING → STOPPED。
核心:用 VarHandle 的 compareAndSet 确保状态转换的原子性。
public class StateMachine {private volatile int state; // 0: INIT, 1: RUNNING, 2: STOPPEDprivate static final VarHandle STATE_HANDLE;static {try {STATE_HANDLE = MethodHandles.lookup().findVarHandle(StateMachine.class, "state", int.class);} catch (Exception e) {throw new Error(e);}}public boolean start() {return STATE_HANDLE.compareAndSet(this, 0, 1);}public boolean stop() {int currentState;do {currentState = (int) STATE_HANDLE.getVolatile(this);if (currentState != 1) return false; // 必须处于 RUNNING 状态} while (!STATE_HANDLE.compareAndSet(this, 1, 2));return true;}
}
场景 5:内存映射文件的原子操作
需求:直接操作内存映射文件(如实现高性能IPC)。
核心:通过 ByteBuffer 的 VarHandle 实现内存映射区域的原子读写。
public class MemoryMappedFile {private final ByteBuffer buffer;private static final VarHandle INT_HANDLE = MethodHandles.byteBufferViewVarHandle(int.class, ByteOrder.nativeOrder());public MemoryMappedFile(String path, int size) throws IOException {try (FileChannel channel = FileChannel.open(Path.of(path), StandardOpenOption.READ, StandardOpenOption.WRITE)) {buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, size);}}//写入 int 值public void atomicWrite(int value) {INT_HANDLE.setVolatile(buffer, 0, value); // 在偏移量0处写入}// 原子读取 int 值public int atomicRead() {return (int) INT_HANDLE.getVolatile(buffer, 0);}//更新public boolean compareAndSwap(int expected, int newValue) {return INT_HANDLE.compareAndSet(buffer, 0, expected, newValue);}
}
场景 6:线程安全的位图索引
需求:多线程环境下高效管理位图(如布隆过滤器)。
核心:使用 VarHandle 的原子位操作(getAndBitwiseOr / getAndBitwiseAnd)。
public class ConcurrentBitMap {private final long[] bits;private static final VarHandle ARRAY_HANDLE = MethodHandles.arrayElementVarHandle(long[].class);public ConcurrentBitMap(int size) {bits = new long[(size + 63) / 64];}// 原子设置某一位public void setBit(int index) {int arrayIndex = index / 64;int bitOffset = index % 64;long mask = 1L << bitOffset;ARRAY_HANDLE.getAndBitwiseOr(bits, array mask);}// 原子清除某一位public void clearBit(int index) {int arrayIndex = index / 64;int bitOffset = index % 64;long mask = ~(1L << bitOffset);ARRAY_HANDLE.getAndBitwiseAnd(bits, arrayIndex, mask);}
}
场景 7:自定义原子引用数组
需求:实现类似 AtomicReferenceArray 但更轻量的线程安全数组。
核心:利用 VarHandle 直接操作数组元素。
public class SafeArray<T> {private final Object[] array;private static final VarHandle ARRAY_HANDLE;static {ARRAY_HANDLE = MethodHandles.arrayElementVarHandle(Object[].class);}public SafeArray(int size) {array = new Object[size];}// 原子设置元素public void set(int index, T value) {ARRAY_HANDLE.setVolatile(array, index, value);}// 原子获取元素public T get(int index) {return (T) ARRAY_HANDLE.getVolatile(array, index);}// CAS 更新public boolean compareAndSet(int index, T expected, T newValue) {return ARRAY_HANDLE.compareAndSet(array, index, expected, newValue);}
}
场景 8:高效计数器组(Striped Counter)
需求:减少高并发下计数器的缓存行竞争。
核心:使用 VarHandle 分散计数器到不同内存位置。
public class StripedCounter {private final long[] counts;private static final VarHandle COUNT_HANDLE;static {COUNT_HANDLE = MethodHandles.arrayElementVarHandle(long[].class);}public StripedCounter(int stripes) {counts = new long[stripes];}// 根据线程ID选择不同的计数器槽public void increment() {int index = (Thread.currentThread().hashCode() & 0x7FFFFFFF) % counts.length;COUNT_HANDLE.getAndAdd(counts, index, 1L);}// 获取总和(可能不精确)public long sum() {long sum = 0;for (long c : counts) {sum += c;}return sum;}
}
最佳实践总结
- 优先选择
VarHandle而非Unsafe:前者是标准 API,且类型安全。 - 明确内存顺序:根据场景选择
plain/opaque/release-acquire/volatile。 - 减少 CAS 竞争:使用回退策略(如指数退避)或分散热点(Striping)。
- 注意可见性:跨线程操作必须使用
volatile或release-acquire模式。
11.底层优化方案
1. 伪共享(False Sharing)与缓存行对齐
问题根源
- 伪共享:两个线程频繁修改位于同一缓存行(通常 64 字节)的不同变量,导致缓存行无效化,引发 CPU 缓存同步开销。
- 后果:高并发场景下性能急剧下降,即使变量逻辑无关。
解决方案:缓存行填充
通过填充变量,确保每个核心变量独占一个缓存行。
代码示例:线程安全的高性能计数器(避免伪共享)
import java.lang.invoke.VarHandle;
.lang.invoke.MethodHandles;class PaddedCounter {// 核心计数变量 + 前后填充(确保独占缓存行)private volatile long p1, p2, p3, p4, p5, p6, p7; // 前填充(56字节)private volatile long count;private volatile long q1, q2, q3, q4, q5, q6, q7; // 后填充(56字节)private static final VarHandle COUNT_HANDLE;static {try {COUNT_HANDLE = MethodHandles.lookup().findVarHandle(PaddedCounter.class, "count", long.class);} catch (Exception e) {throw new Error(e);}}public void increment() {COUNT_HANDLE.getAndAdd(this, 1L);}public long get() {return (long) COUNT_HANDLE.getVolatile(this);}
}
优化原理
- 填充字段:
p1-p7和q1-q7每个long占 8 字节,共 7 * 8=56 字节,加上count的 8 字节,总计 56+56=120 字节,远超 64 字节缓存行,确保count独占一行。 - Volatile 模式:
getVolatile保证跨线程可见性,但填充避免了伪共享导致的性能损失。
2. 使用 @Contended 注解(JVM 自动填充)
Java 8+ 提供 @sun.misc.Contended 注解,由 JVM 自动填充字段(需启用 -XX:-RestrictContended)。
代码示例
import sun.misc.Contended;class ContendedCounter {@Contended // JVM 自动填充private volatile long count;private static final VarHandle COUNT_HANDLE;static {try {COUNT_HANDLE = MethodHandles.lookup().findVarHandle(ContendedCounter.class, "count", long.class);} catch (Exception e) {throw new Error(e);}}public void increment() {COUNT_HANDLE.getAndAdd(this, 1L);}
}
3. 内存屏障(Memory Barrier)的精细化控制
VarHandle 的内存模式(plain/opaque/release/acquire/volatile)直接影响 JVM 插入的内存屏障指令数量。
| 内存模式 | 内存屏障 | 性能开销 | 适用场景 |
|---|---|---|---|
| Plain | 无屏障 | 最低 | 单线程或线程封闭变量 |
| Opaque | 原子性屏障(无顺序保证) | 低 | 线程间通信,但不要求全局顺序 |
| Release | 写屏障(StoreStore + StoreLoad) | 中 | 发布数据到其他线程 |
| Acquire | 读屏障(LoadLoad + LoadStore) | 中 | 获取其他线程发布的数据 |
| Volatile | 全屏障(Load + Store) | 最高 | 严格的 happens-before 语义 |
示例:选择最轻量级屏障
class LightweightSync {private int value;private static final VarHandle VALUE_HANDLE;static {try {VALUE_HANDLE = MethodHandles.lookup().findVarHandle(LightweightSync.class, "value", int.class);} catch (Exception e) {throw new Error(e);}}// 使用 Release 模式写入(仅插入必要屏障)public void publish(int newValue) {VALUE_HANDLE.setRelease(this, newValue);}// 使用 Acquire 模式读取public int read() {return (int) VALUE_HANDLE.getAcquire(this);}
}
4. 直接内存(堆外内存)操作优化
通过 VarHandle 直接操作堆外内存(如 Netty 的 ByteBuf),避免 JVM 堆 GC 开销。
示例:高性能堆外计数器
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.lang.invoke.VarHandle;public class DirectMemoryCounter {private final ByteBuffer buffer;private static final VarHandle LONG_HANDLE;static {LONG_HANDLE = MethodHandles.byteBufferViewVarHandle(long[].class, ByteOrder.nativeOrder());}public DirectMemoryCounter() {buffer = ByteBuffer.allocateDirect(64); // 分配 64 字节堆外内存buffer.order(ByteOrder.nativeOrder());}// 原子递增(无锁)public long increment() {return (long) LONG_HANDLE.getAndAdd(buffer, 0, 1L);}// 直接读取public long get() {return (long) LONG_HANDLE.getVolatile(buffer, 0);}
}
5. 字段偏移量硬编码(极端优化)
在已知 JVM 实现的情况下,直接计算字段偏移量(类似 Unsafe),但牺牲可移植性。
示例:手动计算偏移量
class UnsafeStyleCounter {private static final long VALUE_OFFSET;private volatile long value;static {try {// 假设对象头为 12 字节(32位 JVM)或 16 字节(64位 JVM)VALUE_OFFSET = 16; // 手动计算偏移量(极端情况)} catch (Exception e) {throw new Error(e);}}private static final VarHandle VALUE_HANDLE = MethodHandles.byteArrayViewVarHandle(long[].class, ByteOrder.nativeOrder()).withInvokeExactBehavior().withInvokeBehavior().withCoordinateConversion((addr, coord) -> addr + VALUE_OFFSET);public void increment() {VALUE_HANDLE.getAndAdd(this, 0L, 1L);}
}
6. 性能测试与工具
检测伪共享
- Linux Perf:
perf stat -e cache-misses java YourProgram - Intel VTune:分析缓存行竞争(False Sharing 事件)。
- JMH:基准测试框架,量化不同优化手段的效果。
JMH 基准测试示例
@BenchmarkMode(Mode.Throughput)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class CounterBenchmark {private PaddedCounter paddedCounter = new PaddedCounter();private ContendedCounter contendedCounter = new ContendedCounter();@Benchmarkpublic void paddedIncrement(Blackhole bh) {paddedCounter.increment();bh.consume(paddedCounter.get());}@Benchmarkpublic void contendedIncrement(Blackhole bh) {contendedCounter.increment();bh.consume(contendedCounter.get());}
}
总结:最佳实践
- 优先解决伪共享:通过填充或
@Contended确保热点变量独占缓存行。 - 选择最小内存屏障:根据场景使用
release/acquire替代volatile。 - 堆外内存优化:直接操作
ByteBuffer或Unsafe分配的内存。 - 量化优化效果:通过 JMH 验证优化是否有效,避免过度设计。
相关文章:
Java高性能并发利器-VarHandle
1. 什么是 VarHandle? VarHandle 是 Java 9 引入的类,用于对变量(对象字段、数组元素、静态变量等)进行低级别、高性能的原子操作(如 CAS、原子读写)。它是 java.util.concurrent.atomic 和 sun.misc.…...
蓝桥杯单片机频率
long int Freq; unsigned int Timer_1000Ms; 加上 TMOD | 0x05; void Timer0Init(void) //0毫秒12.000MHz {AUXR & 0x7F; //定时器时钟12T模式TMOD & 0xF0; //设置定时器模式TMOD | 0x05;TL0 0x00; //设置定时初值TH0 0x00; //设置定时初值TF0 0; //清除TF0标…...
【Qt】【第三方库】spdlog日志模块的使用
版本 spdlog版本:1.5.0 采用1.5.0版本主要基于以下考虑:兼容Qt5.9.X版本和兼容C11。 spdlog 1.5.0下载地址:https://github.com/gabime/spdlog/releases/tag/v1.5.0 摘要 在Qt应用程序开发中,良好的日志系统至关重要。本文将介…...
elementui table禁用全选,一次限制勾选一项。
1、设置属性:selection-change“handleSelectionChange” <el-table:data"taskList"ref"tableDataRefs"selection-change"handleSelectionChange":header-cell-class-name"hideAllCheckbox">function handleSelecti…...
3.1多状态专题:LeetCode面试题17.16 按摩师
动态规划解决按摩师预约问题——以LeetCode面试题17.16为例 1.题目链接 LeetCode面试题17.16 按摩师 2.题目描述 一个有名的按摩师收到一系列的预约请求,每个预约都可以选择接受或不接受。但相邻的预约不能同时接受。给定一个包含各预约时长的数组 nums…...
遵循IEC 62304:构建安全可靠的医疗器械软件
目录 一、IEC 62304 标准概述 1. 标准定位与适用范围 二、核心内容与要求 1. 软件安全等级(Software Safety Classification) (1)分级标准 (2)分级依据 (3)验证要求 2. 软件…...
互联网三高-数据库高并发之分库分表
1 数据库概述 1.1 数据库本身的瓶颈 ① 连接数 MySQL默认最大连接数为100,允许的最大连接数为16384 ② 单表海量数据查询性能 单表最好500w左右,最大警戒线800w ③ 单数据库并发压力问题 MySQL QPS:1500左右/秒 ④ 系统磁盘IO、CPU瓶颈 1.2 数…...
UE5 在UE中创建骨骼动画
文章目录 创建动画的三种方式修改骨骼动画 创建动画的三种方式 方法一 打开一个已有的动画,左上角“创建资产/创建动画/参考姿势” 这将创建一个默认的A字形的骨骼,不建议这么做 方法二 打开一个已有的动画,左上角“创建资产/创建动画/当前…...
Day-01 前端 Web - HTMLCSS
目录 一、HTML 基础 1. HTML 简介 2. HTML 基本结构 3. 常用 HTML 标签 二、CSS 基础 1. CSS 简介 2. CSS 引入方式 3. 常用 CSS 选择器 4. 常用 CSS 属性 一、HTML 基础 1. HTML 简介 HTML(HyperText Markup Language)即超文本标记语言&…...
AWS出海合规解决方案:全球业务扩张的技术指南
1. 引言 随着企业加速全球化进程,出海业务面临的合规挑战日益复杂。AWS作为全球领先的云服务提供商,为企业提供了强大的工具和服务,以帮助它们满足各国的合规要求。本文将探讨如何利用AWS服务构建全面的出海合规解决方案。 2. 全球数据合规挑战 在开始讨论具体解决方案之…...
[ctfshow web入门] web38
信息收集 过滤多了php和file if(isset($_GET[c])){$c $_GET[c];if(!preg_match("/flag|php|file/i", $c)){include($c);echo $flag;}}else{highlight_file(__FILE__); }解题 更多解法参考 [ctfshow web入门] web37 我们选个最简单的。但是因为php被过滤了我们改用…...
汽车CAN总线采样点和采样率详解
写在前面 本篇文章主要讲解在汽车电子中CAN总线采样率的相关知识点,内容涉及CAN波特率、采样点、时间份额、同步跳转宽度以及采样率的计算。 若有相关问题,欢迎评论沟通,共同进步。(*^▽^*) 1、CAN波特率 CAN波特率常规分为250kbps和500kbps,本文章主要以这两个波特率为…...
网络协议学习
最近在适配ESP32的网络驱动,借此机会先学习一下网络通信协议。 以太网帧、IP包及TCP与UDP的报文格式一文读懂网络报问中的检验和(checksum)—— 原理举例代码 提问腾讯元宝提示词: TCP窗口是干什么的拥塞窗口是什么的...
仙剑奇侠传98柔情版游戏秘籍
战斗秘技:在战斗中输入 “cheat”,然后输入 “v” 直接取胜;输入 “y” 敌人不攻击。另外,在战斗中按 “XJPXZ123” 加 “shift” 键,攻击力增加 1000%。等级提升秘籍:当李逍遥等级到达 99 级时…...
Maven error:Could not transfer artifact
问题描述 当项目从私有仓库下载依赖时,Maven 报错,无法从远程仓库下载指定的依赖包,错误信息如下: Could not transfer artifact com.ding.abcd:zabk-java:pom from/to releases (http://192.1122.101/repory/mavenleases/): 此…...
pytorch 反向传播
文章目录 概念计算图自动求导的两种模式 自动求导-代码标量的反向传播非标量变量的反向传播将某些计算移动到计算图之外 概念 核心:链式法则 深度学习框架通过自动计算导数(自动微分)来加快求导。 实践中,根据涉及号的模型,系统会构建一个计…...
WindowsPE文件格式入门06.手写最小PE
https://bpsend.net/thread-346-1-1.html 实现目标 实现目标:手写实现不大于 200 Byte大小的PE文件(又名:畸形PE/变形PE),要求MessageBox弹框显示一个字符串。实现要点:充分利用空间,在保证遵…...
并发编程--互斥锁与读写锁
并发编程–互斥锁与读写锁 文章目录 并发编程--互斥锁与读写锁1. 基本概念2. 互斥锁2.1 基本逻辑2.2 函数接口2.3示例代码12.4示例代码2 3. 读写锁3.1 基本逻辑3.2示例代码 1. 基本概念 互斥与同步是最基本的逻辑概念: 互斥指的是控制两个进度使之互相排斥&#x…...
记录第一次使用H5的WebBluetooth完成蓝牙标签打印机的(踩坑)过程
第1步 首先第一步,调试环境必须是https的,由于浏览器的强制安全策略,本地可以采用localhost 第2步 然后,如果打印需要服务UUID(Service UUID) 和 特征UUID(Characteristic UUID)&…...
2025 年“认证杯”数学中国数学建模网络挑战赛 A题 小行星轨迹预测
近地小行星( Near Earth Asteroids, NEAs )是轨道相对接近地球的小行 星,它的正式定义为椭圆轨道的近日距不大于 1.3 天文单位( AU )的小行星。 其中轨道与地球轨道最近距离小于 0.05A 且直径大于 140 米的小行星被…...
【WRF理论第十七期】单向/双向嵌套机制(含namelist.input详细介绍)
WRF运行的单向/双向嵌套机制 准备工作:WRF运行的基本流程namelist.input的详细设置&time_control 设置&domain 嵌套结构&bdy_control 配置部分 namelist 其他注意事项Registry.EM 运行 ARW 嵌套双向嵌套(two-way nesting)Moving …...
Spring Boot 3.4.3 和 Spring Security 6.4.2 结合 JWT 实现用户登录
在现代 Web 应用中,用户认证和授权是保障系统安全的核心环节。传统的 Session 认证方式在分布式系统或前后端分离场景下存在局限,而 JWT(JSON Web Token)作为一种无状态的认证机制,凭借其轻量、可扩展和跨服务的特性&a…...
Python 实现的运筹优化系统数学建模详解(0-1规划指派问题)
一、引言 在数学建模的广阔领域中,指派问题作为一类经典且重要的组合优化问题,频繁出现在各类实际场景里。例如,在人力资源管理中,如何将不同技能水平的员工高效地分配到各个项目,以实现项目成本最小化或收益最大化&am…...
TCP转发隧道
✅ 功能特性: 1. 高并发支持:采用 threading.Thread socket,可承载多并发连接 2. 异常处理完善:确保线程内异常不会崩溃整个程序 3. 可持续运行:守护线程 主线程监控机制 4. 运行状态监控: • 当前活跃连…...
React 学习 JSX
APP根组件被index.js渲染到public下的index.html下 JS中写 HTML 代码 渲染列表 条件渲染 复杂条件渲染 事件绑定 传递自定义参数 button标签中写箭头函数引用的格式 自定义参数和事件本身对象都想要的情况...
大模型论文:Language Models are Few-Shot Learners(GPT3)
大模型论文:Language Models are Few-Shot Learners(GPT3) 文章地址:https://proceedings.neurips.cc/paper_files/paper/2020/file/1457c0d6bfcb4967418bfb8ac142f64a-Paper.pdf 一、摘要 我们证明了,扩大语言模型的规模在任务无关的 few…...
一周学会Pandas2 Python数据处理与分析-Pandas2数据导出
锋哥原创的Pandas2 Python数据处理与分析 视频教程: 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 任何原始格式的数据载入DataFrame后,都可以使用类似 DataFrame.to_csv()的方法输出到相应格式的文件或者…...
深入解析栈式虚拟机与反向波兰表示法
1.1 什么是虚拟机? 虚拟机(Virtual Machine, VM)是一种软件实现的计算机系统,提供与物理计算机相类似的环境,但在软件层面运行。虚拟机的存在简化了跨平台兼容性、资源管理以及安全隔离等问题。 1.2 栈式虚拟机的架构…...
python中的数据模型-pydantic浅讲
数据模型-pydantic 1. 基本用法 通过继承 BaseModel,你可以定义一个数据模型类。类的属性使用类型注解来声明字段的类型 from pydantic import BaseModelclass User(BaseModel):name: strage: intis_active: bool True # 默认值字段类型:每个字段…...
15.【.NET 8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--如何拆分单体
单体应用(Monolithic Application)是指将所有功能模块集中在一个代码库中构建的应用程序。它通常是一个完整的、不可分割的整体,所有模块共享相同的运行环境和数据库。这种架构开发初期较为简单,部署也较为方便,但随着…...
