Java高性能并发利器-VarHandle

news2025/4/15 13:58:34

1. 什么是 VarHandle?​

VarHandle 是 Java 9 引入的类,用于对变量(对象字段、数组元素、静态变量等)进行低级别、高性能的原子操作(如 CAS、原子读写)。它是 java.util.concurrent.atomic 和 sun.misc.Unsafe 的安全替代品,提供类型安全和规范化的内存顺序控制。


2. 获取 VarHandle 的 4 种方式

​(1) 实例字段

class MyClass {
    private int value;

    // 创建 VarHandle
    static 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 的对比

特性VarHandleUnsafe
类型安全✔️ 强类型检查❌ 依赖偏移量和手动类型转换
内存顺序控制✔️ 提供明确语义❌ 需要开发者自行管理屏障
兼容性✔️ 标准 API,长期支持❌ 内部 API,可能被移除
访问权限✔️ 受 MethodHandles.Lookup 限制❌ 可绕过 Java 访问控制

7. 性能优化建议

  1. 优先使用 volatile 模式​:在需要全局可见性时使用 getVolatile/setVolatile
  2. 避免反射开销​:将 VarHandle 定义为 static final 常量。
  3. 减少 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 支持哪些数据类型?​

  • 基本类型:intlongdouble, 等
  • 对象引用:Object
  • 数组:任意类型的数组元素

9. 总结

VarHandle 是 Java 并发编程的利器,适用于:

  • 实现高性能无锁数据结构
  • 替代 AtomicXXX 类减少开销
  • 直接操作堆外内存或数组

​10. 场景

场景 1:高性能环形缓冲区(无锁队列)​

需求​:实现多生产者-多消费者的环形缓冲区,避免锁竞争。
核心​:利用 VarHandlegetAndAddcompareAndSet 实现无锁指针推进。

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 开销。
核心​:用 VarHandlecompareAndExchange 替代双重检查锁,性能更高。

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,则替换为 newRes
            res = (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.floatToIntBitsVarHandlegetAndBitwiseXor 模拟原子操作。

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:状态机的高效切换

需求​:多线程环境下安全切换状态,支持从 INITRUNNINGSTOPPED
核心​:用 VarHandlecompareAndSet 确保状态转换的原子性。

public class StateMachine {
    private volatile int state; // 0: INIT, 1: RUNNING, 2: STOPPED

    private 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)。
核心​:通过 ByteBufferVarHandle 实现内存映射区域的原子读写。

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;
    }
}

最佳实践总结

  1. 优先选择 VarHandle 而非 Unsafe:前者是标准 API,且类型安全。
  2. 明确内存顺序​:根据场景选择 plain/opaque/release-acquire/volatile
  3. 减少 CAS 竞争​:使用回退策略(如指数退避)或分散热点(Striping)。
  4. 注意可见性​:跨线程操作必须使用 volatilerelease-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();

    @Benchmark
    public void paddedIncrement(Blackhole bh) {
        paddedCounter.increment();
        bh.consume(paddedCounter.get());
    }

    @Benchmark
    public void contendedIncrement(Blackhole bh) {
        contendedCounter.increment();
        bh.consume(contendedCounter.get());
    }
}

总结:最佳实践

  1. 优先解决伪共享​:通过填充或 @Contended 确保热点变量独占缓存行。
  2. 选择最小内存屏障​:根据场景使用 release/acquire 替代 volatile
  3. 堆外内存优化​:直接操作 ByteBuffer 或 Unsafe 分配的内存。
  4. 量化优化效果​:通过 JMH 验证优化是否有效,避免过度设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2334310.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

蓝桥杯单片机频率

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标…

遵循IEC 62304:构建安全可靠的医疗器械软件

目录 一、IEC 62304 标准概述 1. 标准定位与适用范围 二、核心内容与要求 1. 软件安全等级&#xff08;Software Safety Classification&#xff09; &#xff08;1&#xff09;分级标准 &#xff08;2&#xff09;分级依据 &#xff08;3&#xff09;验证要求 2. 软件…

互联网三高-数据库高并发之分库分表

1 数据库概述 1.1 数据库本身的瓶颈 ① 连接数 MySQL默认最大连接数为100&#xff0c;允许的最大连接数为16384 ② 单表海量数据查询性能 单表最好500w左右&#xff0c;最大警戒线800w ③ 单数据库并发压力问题 MySQL QPS&#xff1a;1500左右/秒 ④ 系统磁盘IO、CPU瓶颈 1.2 数…

UE5 在UE中创建骨骼动画

文章目录 创建动画的三种方式修改骨骼动画 创建动画的三种方式 方法一 打开一个已有的动画&#xff0c;左上角“创建资产/创建动画/参考姿势” 这将创建一个默认的A字形的骨骼&#xff0c;不建议这么做 方法二 打开一个已有的动画&#xff0c;左上角“创建资产/创建动画/当前…

[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,本文章主要以这两个波特率为…

Maven error:Could not transfer artifact

问题描述 当项目从私有仓库下载依赖时&#xff0c;Maven 报错&#xff0c;无法从远程仓库下载指定的依赖包&#xff0c;错误信息如下&#xff1a; Could not transfer artifact com.ding.abcd:zabk-java:pom from/to releases (http://192.1122.101/repory/mavenleases/): 此…

pytorch 反向传播

文章目录 概念计算图自动求导的两种模式 自动求导-代码标量的反向传播非标量变量的反向传播将某些计算移动到计算图之外 概念 核心&#xff1a;链式法则 深度学习框架通过自动计算导数(自动微分)来加快求导。 实践中&#xff0c;根据涉及号的模型&#xff0c;系统会构建一个计…

WindowsPE文件格式入门06.手写最小PE

https://bpsend.net/thread-346-1-1.html 实现目标 实现目标&#xff1a;手写实现不大于 200 Byte大小的PE文件&#xff08;又名&#xff1a;畸形PE/变形PE&#xff09;&#xff0c;要求MessageBox弹框显示一个字符串。实现要点&#xff1a;充分利用空间&#xff0c;在保证遵…

并发编程--互斥锁与读写锁

并发编程–互斥锁与读写锁 文章目录 并发编程--互斥锁与读写锁1. 基本概念2. 互斥锁2.1 基本逻辑2.2 函数接口2.3示例代码12.4示例代码2 3. 读写锁3.1 基本逻辑3.2示例代码 1. 基本概念 互斥与同步是最基本的逻辑概念&#xff1a; 互斥指的是控制两个进度使之互相排斥&#x…

记录第一次使用H5的WebBluetooth完成蓝牙标签打印机的(踩坑)过程

第1步 首先第一步&#xff0c;调试环境必须是https的&#xff0c;由于浏览器的强制安全策略&#xff0c;本地可以采用localhost 第2步 然后&#xff0c;如果打印需要服务UUID&#xff08;Service UUID&#xff09; 和 特征UUID&#xff08;Characteristic UUID&#xff09;&…

【WRF理论第十七期】单向/双向嵌套机制(含namelist.input详细介绍)

WRF运行的单向/双向嵌套机制 准备工作&#xff1a;WRF运行的基本流程namelist.input的详细设置&time_control 设置&domain 嵌套结构&bdy_control 配置部分 namelist 其他注意事项Registry.EM 运行 ARW 嵌套双向嵌套&#xff08;two-way nesting&#xff09;Moving …

React 学习 JSX

APP根组件被index.js渲染到public下的index.html下 JS中写 HTML 代码 渲染列表 条件渲染 复杂条件渲染 事件绑定 传递自定义参数 button标签中写箭头函数引用的格式 自定义参数和事件本身对象都想要的情况

大模型论文:Language Models are Few-Shot Learners(GPT3)

大模型论文&#xff1a;Language Models are Few-Shot Learners(GPT3) 文章地址&#xff1a;https://proceedings.neurips.cc/paper_files/paper/2020/file/1457c0d6bfcb4967418bfb8ac142f64a-Paper.pdf 一、摘要 我们证明了&#xff0c;扩大语言模型的规模在任务无关的 few…

一周学会Pandas2 Python数据处理与分析-Pandas2数据导出

锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 任何原始格式的数据载入DataFrame后&#xff0c;都可以使用类似 DataFrame.to_csv()的方法输出到相应格式的文件或者…

深入解析栈式虚拟机与反向波兰表示法

1.1 什么是虚拟机&#xff1f; 虚拟机&#xff08;Virtual Machine, VM&#xff09;是一种软件实现的计算机系统&#xff0c;提供与物理计算机相类似的环境&#xff0c;但在软件层面运行。虚拟机的存在简化了跨平台兼容性、资源管理以及安全隔离等问题。 1.2 栈式虚拟机的架构…

学习MySQL的第八天

海到无边天作岸 山登绝顶我为峰 一、数据库的创建、修改与删除 1.1 引言 在经过前面七天对于MySQL基本知识的学习之后&#xff0c;现在我们从基本的语句命令开始进入综合性的语句的编写来实现特定的需求&#xff0c;从这里开始需要我们有一个宏观的思想&…

AI识别与雾炮联动:工地尘雾治理新途径

利用视觉分析的AI识别用于设备联动雾炮方案 背景 在建筑工地场景中&#xff0c;人工操作、机械作业以及环境因素常常导致局部出现大量尘雾。传统监管方式存在诸多弊端&#xff0c;如效率低、资源分散、监控功能单一、人力效率低等&#xff0c;难以完美适配现代工程需求。例如…

GD32F303-IAP的过程和实验

使用的芯片为GD32F303VC 什么是IAP呢&#xff1f;有个博主写的很清楚&#xff1b;就是远程升级&#xff1b; 【单片机开发】单片机的烧录方式详解&#xff08;ICP、IAP、ISP&#xff09;_isp烧录-CSDN博客 我们需要写一个boot 和APP 通过 boot对APP的程序进行更新&#xf…

众趣科技助力商家“以真示人”,让消费场景更真实透明

在当今的消费环境中&#xff0c;消费者权益保护问题日益凸显。无论是网购商品与实物不符、预定酒店民宿与图文描述差异大&#xff0c;还是游览景区遭遇“照骗”&#xff0c;这些问题不仅让消费者在消费和决策过程中倍感困扰&#xff0c;也让商家面临信任危机。 消费者在享受便…