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

原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder

原子类

JDK提供的原子类,即Atomic*类有很多,大体可做如下分类:

形式类别举例
Atomic*基本类型原子类AtomicInteger、AtomicLong、AtomicBoolean
Atomic*Array数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
Atomic*Reference引用类型原子类AtomicReference、AtomicStampedReference、AtomicMarkableReference
Atomic*FieldUpdater升级类型原子类AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
*Adder自增器LongAdder、DoubleAdder
*Accumulator累加器LongAccumulator、DoubleAccumulator

引入原因

JDK为何要引入如此多的原子类API。

因为Java中的运算操作,如自增(++)或自减(–)都不是原子性操作,若没有进行额外的同步操作,在多线程环境下就是线程不安全。给变量增加volatile关键词也不管用。
volatile的作用是:

  • 可见性:对volatile变量所有的写操作都能立即反应到其他线程中;
  • 有序性:禁止指令的重排序优化。

并不能保证自增或自减操作的原子性。

AtomicLong

JDK1.5引入的AtomicLong,作用是对长整形对象进行原子操作。类似地,AtomicInteger用于对整形对象进行原子操作;AtomicBoolean用于对Boolean对象进行原子操作。这几个API的方法非常相似。

示例

直接给出代码:

public class AtomicLongExample {private static final AtomicLong counter = new AtomicLong();public static void increment() {counter.incrementAndGet();}public static long get() {return counter.get();}
}

可知:实现起来非常简单。

原理

看看AtomicLong.incrementAndGet()源码:

public class AtomicLong extends Number implements Serializable {private static final Unsafe U = Unsafe.getUnsafe();private static final long VALUE = U.objectFieldOffset(AtomicLong.class, "value");public final long incrementAndGet() {return U.getAndAddLong(this, VALUE, 1L) + 1L;}
}

继续看Unsafe类的getAndAddLong方法:

@IntrinsicCandidate
public final long getAndAddLong(Object o, long offset, long delta) {long v;do {v = getLongVolatile(o, offset);} while (!weakCompareAndSetLong(o, offset, v, v + delta));return v;
}@IntrinsicCandidate
public native long getLongVolatile(Object o, long offset);// weakCompareAndSetLong方法最后调用
@IntrinsicCandidate
public final native boolean compareAndSetLong(Object o, long offset, long expected, long x);

最后是调用native方法。通过Unsafe的CAS指令实现线程安全地、原子性自增操作。

问题

这里提前给出结论,这也是JDK1.8引入LongAdder类的原因:
在多线程竞争不激烈的情况下,这样做是合适的。但是如果线程竞争激烈,会造成大量线程在原地打转、不停尝试去修改值,但再次发现值已被修改,于是继续自旋。浪费大量的CPU资源。

AtomicLong持有的成员变量value是volatile关键字修饰的,线程修改临界资源后,需要刷新到其他线程,也是要费一番功夫的。

严重情况下,volatile可能导致总线风暴问题。

AtomicReference

AtomicReference是JDK1.5开始提供的一种用于原子操作对象引用的类,位于java.util.concurrent.atomic包。提供一种非阻塞的线程安全方式来更新和读取对象引用,使用的是底层的原子操作来保证操作的原子性。

适用场景

  1. 非阻塞算法:在多线程环境下需要实现高效、低延迟的非阻塞算法时,AtomicReference是一个很好的选择。它通过CAS操作避免传统锁机制的开销,适用于对性能要求高的场景;
  2. 引用类型的原子更新:当需要对引用类型(如对象)的更新操作保持原子性时,可使用AtomicReference。例如,在单例模式中,通过CAS操作来确保单例实例的唯一性;
  3. 构建高效的并发数据结构:可以用于构建各种并发数据结构,如无锁队列、无锁栈、无锁链表等;
  4. 实现不可变对象的原子替换:对于不可变对象,可使用AtomicReference实现原子替换操作,保证在多线程环境下的安全性。例如,引用类型的配置更新,确保配置更新的原子性和可见性。

实例

使用AtomicReference实现简单CAS操作:

@Slf4j
public class AtomicReferenceExample {public static void main(String[] args) {AtomicReference<String> atomicString = new AtomicReference<>("initialValue");log.info("Current value: " + atomicString.get());// 使用compareAndSet原子更新值boolean success = atomicString.compareAndSet("initialValue", "newValue");log.info("Updated value: " + atomicString.get());// 直接设置新值atomicString.set("anotherValue");log.info("Directly set value: " + atomicString.get());}
}

可知:和AtomicLong非常相似。

原理

  1. CAS操作(Compare-And-Set):基于硬件支持的CAS原子操作实现。这种操作包括三个步骤:比较当前值是否等于预期值,如果相等则将其更新为新值,如果不相等则不进行任何操作。CAS是一种无锁(lock-free)算法,可避免传统锁机制带来的性能问题和死锁风险。
  2. 内存可见性:使用volatile关键字确保引用变量的可见性。所有对AtomicReference的写操作都会立即对所有线程可见,读取操作也总是能获取最新的值。

AtomicReference提供的一系列方法:

  • get():获取当前的引用值;
  • set(V newValue):设置当前引用值为新值;
  • lazySet(V newValue):惰性设置为新值;
  • compareAndSet(V expect, V update):如果当前引用值等于预期值,则将其更新为新值;
  • getAndSet(V newValue):获取当前引用值并设置为新值;
  • weakCompareAndSet(V expect, V update):类似于compareAndSet,但在一些平台上可能有更高的性能;
  • weakCompareAndSetPlain(V expectedValue, V newValue)
  • getAndUpdate(UnaryOperator<V> updateFunc)
  • updateAndGet(UnaryOperator<V> updateFunc)
  • getAndAccumulate(V x, BinaryOperator<V> accumulatorFunc)
  • accumulateAndGet(V x, BinaryOperator<V> accumulatorFunc)

JDK9又新增一系列方法:

  • getPlain
  • setPlain
  • getOpaque
  • setOpaque
  • getAcquire
  • setRelease
  • compareAndExchange
  • compareAndExchangeAcquire
  • compareAndExchangeRelease
  • weakCompareAndSetVolatile
  • weakCompareAndSetAcquire
  • weakCompareAndSetRelease

总结

AtomicReference是一种高效、线程安全的工具,用于在并发环境中进行原子引用操作。它依赖于CAS操作来实现无锁的原子性更新,适用于构建高性能的并发数据结构和非阻塞算法。在实际应用中,可根据具体需求选择使用AtomicReference来替代传统的锁机制,以提高并发程序的性能和可靠性。

AtomicIntegerFieldUpdater

AtomicXXXFieldUpdater是JDK提供的一种用于更新对象中某些字段值的工具,提供一种低开销、高性能的方式来对对象的字段进行原子操作。适合某些特定场景,尤其是在需要对对象的整型字段实现线程安全更新时。包括:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater和AtomicReferenceFieldUpdater。下面以AtomicIntegerFieldUpdater为例讲解。

适用场景:

  • 高性能计数器或标志位更新:需要频繁更新对象中的某个计数器或标志字段,但又不想将整个对象进行锁定;
  • 基于 POJO 对象的非静态字段更新:如果字段不能声明为 AtomicInteger(如 POJO 中的普通整型字段),AtomicIntegerFieldUpdater 提供了原子化更新的方法;
  • 内存优化场景:相比直接使用AtomicInteger,通过AtomicIntegerFieldUpdater不需要为每个整型字段额外创建一个AtomicInteger对象;
  • 避免锁开销:替代传统的synchronized或ReentrantLock,减少线程间竞争和锁的性能开销。适合高并发环境下的小粒度操作;
  • 共享对象字段的线程安全管理:在缓存、计数器池等场景中,共享对象的某个字段需要被多个线程安全地读写。

AtomicIntegerFieldUpdater的核心优势在于提供对对象字段的原子操作,节省内存,减少锁开销。适用于高性能的计数或标志更新场景,但由于功能较为有限,更多的复杂线程同步需求可能需要其他工具(如Lock或ConcurrentHashMap)。

示例

假设需要对某个对象的int字段count进行线程安全的递增操作:

public class Example {// 字段必须是volatile、非静态、int基础类型private volatile int count;// 创建 AtomicIntegerFieldUpdaterprivate static final AtomicIntegerFieldUpdater<Example> updater = AtomicIntegerFieldUpdater.newUpdater(Example.class, "count");public int increment() {return updater.incrementAndGet(this); // 原子递增}public int get() {return updater.get(this); // 获取值}public static void main(String[] args) {Example example = new Example();log.info(example.increment()); // 输出:1}
}

原理

AtomicIntegerFieldUpdater是一个抽象泛型类,构造函数是protected,不能直接构造其对象,必须通过它提供的一个静态方法来创建:

// 受保护的不执行任何操作的构造函数,供子类使用
protected AtomicIntegerFieldUpdater() {
}@CallerSensitive
public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
}

newUpdater()静态方法传入的是要修改的类和对应的成员变量的名字,内部通过反射拿到这个类的成员变量,然后包装成一个AtomicIntegerFieldUpdater对象(即AtomicIntegerFieldUpdaterImpl)。所以,这个对象表示的是类的某个成员,而不是对象的成员变量。

然后可使用其一系列方法:

  • compareAndSet
  • weakCompareAndSet
  • set
  • lazySet
  • get
  • getAndSet
  • getAndIncrement
  • getAndDecrement
  • getAndAdd
  • incrementAndGet
  • decrementAndGet
  • addAndGet
  • getAndUpdate
  • updateAndGet
  • getAndAccumulate
  • accumulateAndGet

以getAndAdd方法为例,其源码如下:

public int getAndAdd(T obj, int delta) {int prev, next;do {prev = get(obj);next = prev + delta;} while (!compareAndSet(obj, prev, next));return prev;
}

get方法如下:

public final int get(T obj) {accessCheck(obj);return U.getIntVolatile(obj, offset);
}

compareAndSet方法如下:

public final boolean compareAndSet(T obj, int expect, int update) {accessCheck(obj);return U.compareAndSetInt(obj, offset, expect, update);
}

accecssCheck方法检查该obj是不是cclass类型,如果不是,则拒绝修改并抛出异常。

U是Unsafe,使用其CAS方法,参考Unsafe入门讲解。

AtomicIntegerFieldUpdaterImpl是一个静态私有内部实现类Impl,其构造函数为:

AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName, final Class<?> caller) {final Field field;final int modifiers;try {field = AccessController.doPrivileged(new PrivilegedExceptionAction<Field>() {public Field run() throws NoSuchFieldException {return tclass.getDeclaredField(fieldName);}});modifiers = field.getModifiers();sun.reflect.misc.ReflectUtil.ensureMemberAccess(caller, tclass, null, modifiers);ClassLoader cl = tclass.getClassLoader();ClassLoader ccl = caller.getClassLoader();if ((ccl != null) && (ccl != cl) && ((cl == null) || !isAncestor(cl, ccl))) {sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);}} catch (PrivilegedActionException pae) {throw new RuntimeException(pae.getException());} catch (Exception ex) {throw new RuntimeException(ex);}if (field.getType() != int.class)throw new IllegalArgumentException("Must be integer type");if (!Modifier.isVolatile(modifiers))throw new IllegalArgumentException("Must be volatile type");// 受保护字段成员的访问仅限于访问类或其子类之一的接收者,并且访问类又必须是受保护成员定义类的子类(或包兄弟)// 如果更新程序引用当前包之外的声明类的受保护字段,则接收者参数将缩小到访问类的类型this.cclass = (Modifier.isProtected(modifiers) && tclass.isAssignableFrom(caller) && !isSamePackage(tclass, caller)) ? caller : tclass;this.tclass = tclass;this.offset = U.objectFieldOffset(field);
}

可知:要想使用AtomicIntegerFieldUpdater修改成员变量,成员变量必须是volatile的int类型(不能是包装类)。

对比

工具特点适用场景
AtomicIntegerFieldUpdater低内存开销,对对象的字段进行原子更新对对象的单一字段进行高性能原子操作
AtomicInteger独立对象的原子更新,使用简单,但需要额外的内存空间独立计数器或标志位
synchronized/Lock适合复杂的临界区保护复杂的线程同步逻辑
LongAdder提供高并发场景下的高效累加器,减少线程争用高并发场景的全局计数器

LongAdder

JDK1.8中新加入一个原子类LongAdder,该类可保证Long类型操作的原子性。相对于AtomicLong,LongAdder有着更高的性能(减少乐观锁的重试次数)和更好的表现,可完全替代AtomicLong来进行原子操作。

当大量线程同时访问AtomicLong时,会因为大量线程执行CAS操作失败而进行空旋转,导致CPU资源消耗过多,执行效率不高。

示例

直接给出代码:

public class LongAdderExample {private static final LongAdder counter = new LongAdder();public static void increment() {counter.increment();}public static long get() {return counter.sum();}
}

可见:实现起来非常简单。

原理

基于CAS分段锁的思想实现的。线程去读写一个LongAdder类型的变量时的流程:
在这里插入图片描述
LongAdder基于Unsafe提供的CAS操作+valitale去实现的。在LongAdder的父类Striped64中维护着base变量和cells数组,当多个线程操作一个变量时,先会在这个base变量上进行CAS操作,当它发现线程增多时,就会使用cells数组。比如当base将要更新时发现线程增多(调用casBase方法更新base值失败),则会自动使用cells数组,每一个线程对应于一个cell,在每一个线程中对该cells进行CAS操作,这样就可以将单一value的更新压力分担到多个value中去,降低单个value的热度,同时也减少大量线程的空转,提高并发效率,分散并发压力。这种分段锁需要额外维护一个内存空间cells,在高并发场景下,这点成本几乎可忽略。

利用空间来换时间,将热点value分散成一个Cell列表来承接并发的CAS,以此来提升性能。

Benchmark

一个简单不太严谨的Benchmark性能测试:

@Slf4j
public class AtomicLongTester {private static AtomicLong numA = new AtomicLong(0);private static LongAdder numB = new LongAdder();public static void main(String[] args) throws InterruptedException {for (int i = 1; i < 10001; i*=10) {test(false, i);test(true, i);}}public static void test(boolean isLongAdder, int threadCount) throws InterruptedException {long starTime = System.currentTimeMillis();final CountDownLatch latch = new CountDownLatch(threadCount);for (int i = 0; i < threadCount; i++) {new Thread(new Runnable() {public void run() {for (int i = 0; i < 100000; i++) {if (isLongAdder) {numB.add(1);} else {numA.addAndGet(1);}}latch.countDown();}}).start();}// 等待所有运算结束        latch.await();if (isLongAdder) {log.info("Thread Count=" + threadCount + ", LongAdder cost ms=" + (System.currentTimeMillis() - starTime) + ", Result=" + numB.sum());} else {log.info("Thread Count=" + threadCount + ", AtomicLong cost ms=" + (System.currentTimeMillis() - starTime) + ", Result=" + numA.get());}numA = new AtomicLong(0);numB = new LongAdder();}
}

某次运行结果:

Thread Count=1, AtomicLong cost ms=9, Result=100000
Thread Count=1, LongAdder cost ms=13, Result=100000
Thread Count=10, AtomicLong cost ms=14, Result=1000000
Thread Count=10, LongAdder cost ms=41, Result=1000000
Thread Count=100, AtomicLong cost ms=111, Result=10000000
Thread Count=100, LongAdder cost ms=45, Result=10000000
Thread Count=1000, AtomicLong cost ms=1456, Result=100000000
Thread Count=1000, LongAdder cost ms=379, Result=100000000
Thread Count=10000, AtomicLong cost ms=17452, Result=1000000000
Thread Count=10000, LongAdder cost ms=3545, Result=1000000000

可见:当线程竞争率比较低时,AtomicLong效率优于LongAdder的,但当线程竞争率增大时,可看出LongAdder的性能远远高于AtomicLong。

对比

对比项AtomicLongLongAdder
原理Unsafe类CAS指令分段累加;使用内部的多个Cell(类似于分段桶),每个线程可独立更新不同Cell,减少竞争
空间开销只需一个long变量,内存占用小内部包含多个Cell,每个Cell是一个独立变量,占用更多内存
低并发更新只需要操作单一变量,执行路径更短;性能较优且实现简单需初始化多个Cell,即使只有一个线程使用,也需要额外的内存和初始化开销
高并发多线程更新同一变量时,频繁CAS重试会导致性能瓶颈减少线程争用,吞吐量更高
精度要求高更适合当需要获取总值时,会将所有Cell的值汇总;短时间内的结果可能不完全一致

LongAccumulator

有待学习。

参考

相关文章:

原子类、AtomicLong、AtomicReference、AtomicIntegerFieldUpdater、LongAdder

原子类 JDK提供的原子类&#xff0c;即Atomic*类有很多&#xff0c;大体可做如下分类&#xff1a; 形式类别举例Atomic*基本类型原子类AtomicInteger、AtomicLong、AtomicBooleanAtomic*Array数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArrayAtomic…...

c语言——数组名该如何理解呢?

一般情况下&#xff0c;数组名表示首元素地址&#xff0c;以下2种除外&#xff1a; ①、sizeof(数组名) 表示整个数组 ※只有数组名的情况 sizeof&#xff08;数组名i&#xff09; 就不能表示整个数组 ②、&数组名 表示整个数组&#xff0c;取的是整个数…...

Linux学习笔记13 系统进程管理

前文 Linux学习笔记10 系统启动初始化&#xff0c;服务和进程管理&#xff08;上&#xff09;-CSDN博客 Linux学习笔记11 系统启动初始化&#xff0c;服务和进程管理&#xff08;下&#xff09;-CSDN博客 Linux学习笔记12 systemd的其他命令-CSDN博客 之前学习了怎么使用sy…...

Spring Boot 项目集成camunda流程引擎

Spring Boot 项目集成camunda流程引擎 camunda地址 camunda中文地址 使用camunda开源工作流引擎有&#xff1a;通过docker运行、使用springboot集成、部署camunda发行包、基于源代码编译运行等多种方式。 文本重点介绍如何在Spring Boot应用程序中如何集成Camunda Platform开…...

2024.12.2工作复盘

1.今天学了什么&#xff1f; 简单的写了一篇博客&#xff0c;是关于参数校验的问题&#xff0c;参数校验&#xff0c;一个是前后端校验到底一不一致&#xff0c;一个是绕过前端校验&#xff0c;看后台的逻辑到底能不能校验住。 2.今天解决了什么问题&#xff1f; 3.今天完成…...

Hot100 - 二叉树的中序遍历

Hot100 - 二叉树的中序遍历 最佳思路&#xff1a; 中序遍历的顺序是&#xff1a;左子树 -> 根节点 -> 右子树。为了实现这个顺序&#xff0c;我们可以利用栈来模拟递归过程&#xff0c;从而避免栈溢出的问题。在遍历过程中&#xff0c;始终向左子树深入&#xff0c;直到…...

docker build ubuntu ssh

dockerfile 构建镜像 为了使用Dockerfile构建Docker镜像&#xff0c;请遵循以下步骤&#xff1a; 创建一个名为Dockerfile的文件&#xff0c;并在其中定义镜像的构建指令。 FROM swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/ubuntu:24.04# 安装openssh-server和pas…...

三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序

三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序 文章目录 前言三维路径规划|基于黑翅鸢BKA优化算法的三维路径规划Matlab程序基于黑翅鸢BKA优化算法的三维路径规划一、研究基本原理二、黑翅鸢BKA优化算法的基本步骤&#xff1a;三、详细流程四、总结 二、实验结果…...

day01(Linux底层)基础知识

目录 导学 基础知识 1、Bootloader是什么 2、Bootloader的基本作用 3、入式中常见的Bootloader有哪些 4、Linux系统移植为什么要使用bootloader 5、uboot和Bootloader之间的关系 6.Uboot的获取 7、uboot版本命名 8、uboot版本选择 9、uboot的特点 10.Uboot使用 导学…...

flink学习(13)—— 重试机制和维表join

重试机制 当任务出现异常的时候&#xff0c;会直接停止任务——解决方式&#xff0c;重试机制 1、设置checkpoint后&#xff0c;会给任务一个重启策略——无限重启 2、可以手动设置任务的重启策略 代码设置 //开启checkpoint后&#xff0c;默认是无限重启&#xff0c;可以…...

第三方Cookie的消亡与Google服务器端标记的崛起

随着互联网用户对隐私保护的关注日益增强&#xff0c;各大浏览器正在逐步淘汰第三方Cookie。这一变革深刻影响了广告商和数字营销人员的用户跟踪和数据分析方式。然而&#xff0c;Google推出的服务器端标记技术为这一挑战提供了新的解决方案。 什么是第三方Cookie&#xff1f; …...

微信小程序——文档下载功能分享(含代码)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

Burp Suite 全面解析:开启你的 Web 安全测试之旅

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…...

Oracle DataGuard 主备正常切换 (Switchover)

前言 众所周知&#xff0c;DataGuard 的切换分为两种情况&#xff1a; 系统正常情况下的切换&#xff1a;这种方式称为 switchover&#xff0c;是无损切换&#xff0c;不会丢失数据。灾难情况下的切换&#xff1a;这种情况下一般主库已经启动不起来了&#xff0c;称为 failov…...

为什么编程语言会设计不可变的对象?字符串不可变?NSString *s = @“hello“变量s是不可变的吗?Rust内部可变性的意义?

为什么编程语言会设计不可变的对象? Java和C#中String是不可变的&#xff0c;StringBuilder是可变的。Obj-C中NSArray是不可变数组&#xff0c;NSMutableArray是可变数组。编程语言设计不可变的对象其实是为了优化(更高性能和节省存储空间)、安全(包括线程安全)。 字符串不可变…...

安装 RabbitMQ 服务

安装 RabbitMQ 服务 一. RabbitMQ 需要依赖 Erlang/OTP 环境 (1) 先去 RabbitMQ 官网&#xff0c;查看 RabbitMQ 需要的 Erlang 支持&#xff1a;https://www.rabbitmq.com/ 进入官网&#xff0c;在 Docs -> Install and Upgrade -> Erlang Version Requirements (2) …...

爬虫—Scrapy 整合 ChromeDriver 实现动态网页拉取

在进行爬虫开发时&#xff0c;使用 Scrapy 配合 ChromeDriver 来模拟真实浏览器加载 JavaScript 渲染内容是一种常见且高效的方法。Scrapy 本身是一个非常强大的爬虫框架&#xff0c;然而它默认使用的是 requests 库来抓取静态网页内容。对于需要通过 JavaScript 渲染的动态网页…...

Linux 进程管理详解

Linux 进程管理详解 引言 在现代操作系统中&#xff0c;进程是执行程序的基本单位。Linux作为一个强大的多任务操作系统&#xff0c;提供了丰富且灵活的机制来管理和控制进程。本文将详细介绍Linux进程管理的基本概念、核心机制以及常用的管理工具&#xff0c;帮助读者深入了…...

MySQL更新JSON字段key:value形式

MySQL更新JSON字段key:value形式 1. 介绍 ‌MySQL的JSON数据类型‌是MySQL 5.7及以上版本中引入的一种数据类型&#xff0c;用于存储JSON格式的数据。使用JSON数据类型可以自动校验文档是否满足JSON格式的要求&#xff0c;优化存储格式&#xff0c;并允许快速访问文档中的特定…...

vue.js学习(day 18)

实例&#xff1a;面经基础版...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

谷歌浏览器插件

项目中有时候会用到插件 sync-cookie-extension1.0.0&#xff1a;开发环境同步测试 cookie 至 localhost&#xff0c;便于本地请求服务携带 cookie 参考地址&#xff1a;https://juejin.cn/post/7139354571712757767 里面有源码下载下来&#xff0c;加在到扩展即可使用FeHelp…...

JavaSec-RCE

简介 RCE(Remote Code Execution)&#xff0c;可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景&#xff1a;Groovy代码注入 Groovy是一种基于JVM的动态语言&#xff0c;语法简洁&#xff0c;支持闭包、动态类型和Java互操作性&#xff0c…...

Unity3D中Gfx.WaitForPresent优化方案

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

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

Linux离线(zip方式)安装docker

目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1&#xff1a;修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本&#xff1a;CentOS 7 64位 内核版本&#xff1a;3.10.0 相关命令&#xff1a; uname -rcat /etc/os-rele…...