JDK源码

java.util.concurrent

以下是atomic包下的

AtomicInteger

Unsafe类:提供的方法可以直接访问内存、线程。
属性:Unsafe、int value
通过Unsafe方法中的CAS循环,保证int类型值的原子操作

int var5;
do {var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;

AtomicInteger

属性:Unsafe、int value 0、1代表true、false
保证boolean类型值的原子操作

AtomicIntegerArray

属性:Unsafe、int[] array
保证int[]数组中的每一个索引元素的原子操作

AtomicMarkableReference

保证对一个对象和一个boolean类型的标识符的原子操作。

A initialRef = new A();
boolean initialMark = false;
AtomicMarkableReference<A> amr = new AtomicMarkableReference<>(initialRef, initialMark);
boolean[] markHolder = new boolean[1];
A expectedReference = amr.get(markHolder); // amr中的对象引用
boolean expectedMark = markHolder[0]; // amr中的标识符
A newReference = new A();
boolean newMark = true;
System.out.println(amr.compareAndSet(expectedReference, newReference, expectedMark, newMark));

AtomicReference

实现对一个对象引用的原子操作。

AtomicReference<A> ar = new AtomicReference<>();
A origin = ar.get();
// origin = new A();
A newA = new A();
System.out.println(ar.compareAndSet(origin, newA));

AtomicStampedReference

实现对对象引用和int类型的版本戳的原子操作,
解决ABA问题(A修改为B,再修改回A,另一个线程的CAS误认为A没有修改,导致CAS成功)

A initialRef = new A();
int initialStamp = 0;
AtomicStampedReference<A> asr = new AtomicStampedReference<>(initialRef, initialStamp);
int[] stampHolder = new int[1];
A expectedReference = asr.get(stampHolder);
int expectedStamp = stampHolder[0];
A newReference = new A();
int newStamp = expectedStamp + 1;
System.out.println(asr.compareAndSet(expectedReference, newReference, expectedStamp, newStamp));

LongAdder

以空间换时间,内部有多个单元格数组,add时,可能在数组的不同位置进行CAS,避免了CAS的冲突,提高的CAS的成功率。
相较于AtomicInteger,性能高、但内存开销大。

ExecutorService threadPool = Executors.newFixedThreadPool(5);
CountDownLatch countDownLatch = new CountDownLatch(5);
for (int i = 0; i < 5; i++) {threadPool.execute(() -> {for (int j = 0; j < 100000; j++) {la.increment();}countDownLatch.countDown();});
}
countDownLatch.await();
System.out.println(la.sum());
System.out.println(la.intValue());

一下是locks包下的

ReentrantLock

可重入式独占锁。

static int num = 0;
static ReentrantLock rl = new ReentrantLock();public static void main(String[] args) throws InterruptedException {ExecutorService threadPool = Executors.newFixedThreadPool(5);CountDownLatch countDownLatch = new CountDownLatch(2);threadPool.execute(() -> {rl.lock();try {TimeUnit.SECONDS.sleep(3); // 保证第二个线程的tryLock失败num++;} catch (InterruptedException e) {e.printStackTrace();} finally {rl.unlock();}countDownLatch.countDown();;});threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}try {if (rl.tryLock(1, TimeUnit.SECONDS)) {try {num++;} finally {rl.unlock();}}} catch (InterruptedException e) {e.printStackTrace();}countDownLatch.countDown();});countDownLatch.await();System.out.println(num);
}

原理分析

ReentrantLock含有属性Sync,Sync继承AQS(AbstractQueuedSynchronizer)类,
其中AQS中含有属性:unsafe、state、exclusiveOwnerThread,头节点node:head、尾节点node:tail,
其中state=0锁未被使用,state=1代表被使用且未被重入,state=2代表被某个线程使用且重入一次,exclusiveOwnerThread表示持有当前锁的线程。node节点含有属性:prev、next、thread对象,首次初始化时,head=tail=new Node()

reentrantLock.lock();

1、尝试获取锁
尝试通过unsafe.CAS将state从0替换成1(其中公平锁与非公平锁的区别是,非公平锁直接尝试通过CAS将state将0替换成1,而公平锁会判断工作队列中是否有其他等待节点,如果有,就不尝试CAS,如果没有,才会尝试CAS),
如果成功,更新exclusiveOwnerThread=当前线程,逻辑结束,再判断exclusiveOwnerThread是否等于当前线程,如果等于,state++,逻辑结束。

2、将当前线程封装的node加入到等待队列
创建Node,属性thread=当前线程。进行CAS循环,不断尝试将创建的node赋值给tail,且node.prev=原tail,原tail.next=node

3、通过for循环不断尝试获取锁
A.循环逻辑1:判断prev.waitStatus的值,如果等于-1(signal),逻辑结束;如果等于0,通过CAS尝试将waitStatus从0变为-1,如果大于0,清理node的所有waitStatus>0的prev节点,再继续走下一个循环逻辑1。(前驱节点的waitStatus=-1,表示前驱节点释放锁时,会唤醒当前节点(当前线程))
B.循环逻辑2:循环逻辑1中如果成功将前驱节点的waitStatus改为-1,此时通过unsafe.park()将当前线程置为阻塞状态,再通过Thread.interrupted()获取当前线程的中断标志(AQS中,即使线程被中断,也会继续参与锁竞争),如果中断标志为true,循环结束后会调用Thread.currentThread().interrupt();继续修改当前线程的中断标志为true
C.循环逻辑3:判断prev是否是头节点head,如果是,调用第一步的逻辑尝试获取锁,获取失败就继续走下一个循环,如果获取成功,设置头节点head=当前节点
TODO:finally里的逻辑

reentrantLock.unLock();

判断exclusiveOwnerThread是否等于当前线程,如果不等于直接报错。
state–,如果最新的state=0,设置exclusiveOwnerThread=null,且走下面逻辑:
如果head.waitStatus<0,即-1,CAS尝试从-1替换为0,

Condition

实现等待通知机制。

public class MyTest {static ReentrantLock reentrantLock = new ReentrantLock();static Condition condition = reentrantLock.newCondition();static int num = 1;public static void main(String[] args) throws InterruptedException {// 两个线程交替打印two();}private static void two() throws InterruptedException {Thread t1 = new Thread(() -> {for (int i = 1; i < 100; i++) {reentrantLock.lock();try {while (num % 2 == 0) {condition.await(); // 释放锁并等待}System.out.println("线程1===>" + i);condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {reentrantLock.unlock();}}});Thread t2 = new Thread(() -> {for (int i = 1; i < 100; i++) {reentrantLock.lock();try {while (num % 1 == 0) {condition.await(); // 释放锁并等待 }System.out.println("线程2===>" + i);condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();} finally {reentrantLock.unlock();}}});t1.start();t2.start();t1.join();t2.join();System.out.println("END");}
}

ReentrantReadWriteLock

用于优化读多写少场景下的性能。
读写锁不能被同时拥有。
在没有线程拥有写锁的前提下,多个线程可以同时拥有读锁。
在没有线程拥有读锁的前提下,只能有一个线程拥有写锁。
存在问题:拥有读锁不断被使用,导致写锁可能长时间无法获取。

public class MyTest {static int num = 0;static ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock();static ReentrantReadWriteLock.ReadLock readLock = rrwl.readLock();static ReentrantReadWriteLock.WriteLock writeLock = rrwl.writeLock();public static void main(String[] args) throws InterruptedException {ExecutorService threadPool = Executors.newFixedThreadPool(5);CountDownLatch countDownLatch = new CountDownLatch(3);threadPool.execute(() -> {readLock.lock();try {TimeUnit.SECONDS.sleep(4);System.out.println("线程1==>" + num);} catch (InterruptedException e) {e.printStackTrace();} finally {readLock.unlock();}countDownLatch.countDown();});threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}try {if (readLock.tryLock(1, TimeUnit.SECONDS)) {try {System.out.println("线程2==>" + num);} finally {readLock.unlock();}}} catch (InterruptedException e) {e.printStackTrace();}countDownLatch.countDown();});threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}try {if (writeLock.tryLock(1, TimeUnit.SECONDS)) {try {num++;} finally {writeLock.unlock();}}} catch (InterruptedException e) {e.printStackTrace();}countDownLatch.countDown();});countDownLatch.await();System.out.println(num);}
}

StampedLock

读写锁,与ReentrantReadWriteLock的区别是提供一种新的读锁:乐观读锁。
获取乐观读锁的操作并不会阻塞其他线程获取读锁,但是我们要校验读锁的有效性,即中间是否有其他线程获取了写锁,如果有,再尝试获取读锁。

public class MyTest {static int num = 0;static StampedLock sl = new StampedLock();public static void main(String[] args) throws InterruptedException {ExecutorService threadPool = Executors.newFixedThreadPool(5);CountDownLatch countDownLatch = new CountDownLatch(3);threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}long stamp = sl.tryOptimisticRead();if (!sl.validate(stamp)) {stamp = sl.readLock();try {System.out.println(stamp + "悲观线程1===>" + num);} finally {sl.unlockRead(stamp);}} else {System.out.println(stamp + "线程1===>" + num);}countDownLatch.countDown();/*long stamp = sl.readLock();try {TimeUnit.SECONDS.sleep(4);System.out.println(stamp + "线程1===>" + num);} catch (InterruptedException e) {e.printStackTrace();} finally {sl.unlockRead(stamp);}countDownLatch.countDown();*/});threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(4);} catch (InterruptedException e) {e.printStackTrace();}long stamp = sl.tryOptimisticRead();if (!sl.validate(stamp)) {stamp = sl.readLock();try {System.out.println(stamp + "悲观线程2===>" + num);} finally {sl.unlockRead(stamp);}} else {System.out.println(stamp + "线程2===>" + num);}countDownLatch.countDown();});threadPool.execute(() -> {/*try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}*/long stamp = sl.writeLock();try {TimeUnit.SECONDS.sleep(2);num++;} catch (InterruptedException e) {e.printStackTrace();} finally {sl.unlockWrite(stamp);}countDownLatch.countDown();});countDownLatch.await();System.out.println(num);}
}

一下是juc包下的

ArrayBlockingQueue

基于数组实现的有界阻塞队列。

CompletableFuture

四种创建方式:

ExecutorService threadPool = Executors.newFixedThreadPool(5);
CompletableFuture.runAsync(() -> {});
CompletableFuture.runAsync(() -> {}, threadPool);
CompletableFuture.supplyAsync(() -> null);
CompletableFuture.supplyAsync(() -> null, threadPool);

1、阻塞主线程,获取结果

ExecutorService threadPool = Executors.newFixedThreadPool(5);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}return new Random().nextInt(10);
}, threadPool);
Integer join = completableFuture.join(); // 阻塞当前线程

2、任务串行执行
不能先创建CompletableFuture对象,在调用completableFuture.handle() 这样会导致join()先于handle()执行。
方式一:获取上一步的返回结果和异常信息

ExecutorService threadPool = Executors.newFixedThreadPool(5);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("第一步返回结果:" + 1);return 1;
}, threadPool).handle((result, exception) -> {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}if (exception == null) {System.out.println("上一步结果:" + result);} else {System.out.println("上一步异常:");exception.printStackTrace();}return 2;
});

方式二:thenRun()方法异步执行,不影响join()返回结果,所以先执行了join()

ExecutorService threadPool = Executors.newFixedThreadPool(5);
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("第一步返回结果:" + 1);return 1;
}, threadPool);
completableFuture.thenRun(() -> {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("第二步以触发");
});
System.out.println(completableFuture.join());
}

3、任务间的交互

public static void main(String[] args) throws InterruptedException {ExecutorService threadPool = Executors.newFixedThreadPool(5);CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("返回1");return 1;}, threadPool);CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> {try {TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("返回3");return 3;}, threadPool);System.out.println(f1.thenCombine(f2, (r1, r2) -> {System.out.println("r1=" + r1);System.out.println("r2=" + r2);return r1 + r2;}).join());
}

ConcurrentHashMap

多线程环境下可以保证线程安全的map容器。

ConcurrentLinkedDeque

TODO:JRB

ConcurrentLinkedQueue

TODO:JRB

ConcurrentSkipListMap

TODO:JRB

ConcurrentSkipListSet

TODO:JRB

CopyOnWriteArrayList

TODO:JRB

CopyOnWriteArraySet

TODO:JRB

CountDownLatch

通过await()阻塞当前线程执行,直到指定次数的countDown()执行完

CyclicBarrier

cyclicBarrier.await()时,直有该cyclicBarrier的所有的await()都触发时,才会往下执行。
可以用多次。

public static void main(String[] args) throws InterruptedException {ExecutorService threadPool = Executors.newFixedThreadPool(5);CyclicBarrier cyclicBarrier = new CyclicBarrier(3, () -> {System.out.println("3个await()执行完就触发");});threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(1);System.out.println("线程一完成1阶段");cyclicBarrier.await();TimeUnit.SECONDS.sleep(2);System.out.println("线程一完成2阶段");cyclicBarrier.await();TimeUnit.SECONDS.sleep(3);System.out.println("线程一完成3阶段");} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}});threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(2);System.out.println("线程二完成1阶段");cyclicBarrier.await();TimeUnit.SECONDS.sleep(1);System.out.println("线程二完成2阶段");cyclicBarrier.await();TimeUnit.SECONDS.sleep(2);System.out.println("线程二完成3阶段");} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}});threadPool.execute(() -> {try {TimeUnit.SECONDS.sleep(3);System.out.println("线程三完成1阶段");cyclicBarrier.await();TimeUnit.SECONDS.sleep(2);System.out.println("线程三完成2阶段");cyclicBarrier.await();TimeUnit.SECONDS.sleep(1);System.out.println("线程三完成3阶段");} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}});
}

输出结果:
线程一完成1阶段
线程二完成1阶段
线程三完成1阶段
3个await()执行完就触发
线程二完成2阶段
线程一完成2阶段
线程三完成2阶段
3个await()执行完就触发
线程三完成3阶段
线程二完成3阶段
线程一完成3阶段

DelayQueue

TODO:JRB

Exchanger

用于两个线程之间交换数据。

public static void main(String[] args) throws InterruptedException {ExecutorService threadPool = Executors.newFixedThreadPool(5);Exchanger<Integer> exchanger = new Exchanger<>();threadPool.execute(() -> {int result = 0;for (int i = 0; i < 5; i++) {result += i;}Integer sum = Integer.valueOf(result);try {TimeUnit.SECONDS.sleep(3);Integer exchange = exchanger.exchange(sum);System.out.println("线程一收到结果:" + exchange);System.out.println("总和=" + sum + exchange);} catch (InterruptedException e) {e.printStackTrace();}});threadPool.execute(() -> {int result = 0;for (int i = 0; i < 5; i++) {result += i;}Integer sum = Integer.valueOf(result);try {TimeUnit.SECONDS.sleep(1);// 阻塞,知道另一个exchanger.exchange()执行Integer exchange = exchanger.exchange(sum);// 非阻塞,超时会报TimeoutException//Integer exchange = exchanger.exchange(sum, 1, TimeUnit.SECONDS);System.out.println("线程二收到结果:" + exchange);System.out.println("总和=" + sum + exchange);} catch (InterruptedException e) {e.printStackTrace();}});
}

ExecutorCompletionService

TODO:JRB

Executors

TODO:JRB

ForkJoinPool

将一个复杂的大任务递归拆分为多个小任务(fork),直到子任务足够小可以直接处理;然后合并所有子任务的结果(join),得到最终结果。例如:计算 1~1000000 的和,可拆分为 1100000、100001200000 等子任务,分别计算后汇总。

Thread

new Thread().interrupt();
作用:设置目前线程的中断标志为true,此时若目标线程处于阻塞状态(如 sleep()/wait()),会立即抛出 InterruptedException并​​清除中断标志。

new Thread().isInterrupted();
作用:仅查询目前线程的中断标志

Thread.interrupted();
作用:查询当前线程的中断标志,并重置(重置为false)

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

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

相关文章

Linux网络编程【基于UDP网络通信的字典翻译服务】

1. 基本框架&#xff1a;前面我们已近完成了&#xff0c;基于UDP协议的网络通信&#xff0c;但是我们服务器接收到来自客户端的信息即字符串时只是进行了简单的发送会客户端和在日志中回显打印&#xff0c;并没有实际的业务服务。那么接下来&#xff0c;我们就设计一个字典翻译…

Quality Control II: Trimming (二):BBDuk

参考&#xff1a;BBDuk Guide - Archive 在我们了解了如何使用trimmomatic之后&#xff0c;我们开始进一步了解另外一种trim工具BBDuk 首先小编要声明&#xff1a;如果想要完全掌握一个工具是需要较长时间的钻研和学习的&#xff0c;这里呢只是提供BBDuk处理数据的基本逻辑和…

AlmaLinux8 平替 manylinux_2_28-python 的 GPG密钥管理、安装 cuda sdk

0. 下载 AlmaLinux 8 docker 镜像 https://hub.docker.com/r/almalinux/8-base/tags 下载镜像&#xff1a; sudo docker pull almalinux/8-base:8.4 创建一个容器&#xff1a; sudo docker run --gpus all -it --name cudaq_src_py_LHL_06 -v /home/hanmeimei/big…

BM1684X平台:Qwen-2-5-VL图像/视频识别应用

一、 简介 Qwen-2-5-VL 是阿里巴巴通义千问团队推出的多模态大语言模型&#xff08;MLLM&#xff09;&#xff0c;属于 Qwen-2 系列模型的一部分&#xff0c;支持视觉&#xff08;Vision&#xff09;与语言&#xff08;Language&#xff09;的多模态交互。 1、特性 动态分辨…

前端项目工程化配置webpack与vite

webpack与vite一、了解 webpack入口(entry)输出(output)loader插件(plugin)模式(mode)二、项目中使用webpackvue项目react项目三、了解vite构建选项&#xff08;build&#xff09;模块解析&#xff08;Resolve&#xff09;模块处理&#xff08;Module&#xff09;服务器选项&am…

机器学习(3):KNN算法-分类

一、KNN算法 K-近邻算法&#xff08;K-Nearest Neighbors&#xff0c;简称KNN&#xff09;,根据K个邻居样本的类别来判断当前样本的类别&#xff1b;如果一个样本在特征空间中的k个最相似(最邻近)样本中的大多数属于某个类别&#xff0c;则该类本也属于这个类别。一些距离&…

Redis Windows迁移方案与测试

我想将开源软件Redis的主程序和附属程序迁移到Windows平台&#xff0c;目前它只能在Linux上运行&#xff0c;让它可以在Windows 11和Windows Server 2025上运行&#xff0c;这需要考虑Linux操作系统和Windows操作系统的差异&#xff0c;请列举出将Redis在Linux系统上运行的GCC的…

信息安全概述--实验总结

数据链路层--ARP欺骗ARP欺骗原理XP2要与XP3通信&#xff0c;要发送ARP请求&#xff0c;询问XP3的MAC地址kali冒充XP3持续给XP2发送ARP应答&#xff0c;XP2会以为收到的MAC地址是XP3的&#xff0c;实际是kali的之后XP2发送的数据都是发给kali的如果说XP2需要想要访问互联网&…

【Electron】打包后图标不变问题,图标问题

windows上图标未更换。图标已经换了&#xff0c;但新打出的包或是安装后的 exe 图标没有更换。这个时候可以右击你的exe或是安装包点属性&#xff0c;看看图标是否正常&#xff0c;如果这里的图标正常&#xff0c;那其实就是成功的了。主要原因是因为 windows 图标缓存机制导致…

单词拆分 II

题目&#xff1a;思考&#xff1a; 本质上和单词拆分1没什么区别单词拆分1是问能不能拆单词拆分2是问把所有拆的方案列出来要列出所有方案&#xff0c;采用字典树回溯 实现&#xff1a; class Node { public:vector<Node*> check;bool isEnd;Node(int num){for (int i0;i…

国产三防平板电脑是什么?三防平板推荐

国产三防平板电脑&#xff0c;专为应对极端工作环境而生。这类设备集防水、防尘、防摔三大防护性能于一体&#xff0c;通过IP67/IP68防护认证及MIL-STD-810军规标准测试&#xff0c;能在建筑工地、油田勘探、应急救援等恶劣场景中稳定运行。其核心价值在于将消费级平板的智能体…

优思学院|什么是精益生产管理?原则与方法详述

在企业经营中&#xff0c;「利润&#xff1d;价格&#xff0d;成本」这条公式可谓家喻户晓。传统的成本思维通常认为价格由公司设定&#xff0c;而成本则是难以撼动的既定事实。然而&#xff0c;随着市场经济与自由定价机制的成熟&#xff0c;企业逐渐意识到——价格其实是由市…

【银行测试】银行票据项目业务+票据测试点分析(四)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、提示付款 功能…

基于华为开发者空间的Open WebUI数据分析与可视化实战

1 概述 1.1 案例介绍 本案例演示如何在华为开发者空间云主机上搭建Open WebUI环境&#xff0c;结合DeepSeek-R1模型进行数据分析、统计建模、数据可视化和业务洞察挖掘等实际数据科学任务。 1.2 适用对象 数据分析师业务分析师数据科学工程师市场研究人员统计学专业学生 1…

【HZ-T536开发板免费体验】Cangjie Magic调用视觉语言大模型(VLM)真香,是不是可以没有YOLO和OCR了?

目录 引言 编写视觉语言大模型&#xff08;VLM&#xff09;程序 交叉编译Cangjie Magic到T536开发板 对cjpm.toml文件的修改 stdx库的配置 拷贝libsecurec.so到cangjie的库文件中 开始交叉编译 部署到开发板 拷贝所需要的库文件 安装curl 运行程序 结束语 本文首发…

最长连续序列(每天刷力扣hot100系列)

目录 题目介绍&#xff1a; 哈希表法&#xff1a; 复杂度分析&#xff1a; 思路分析&#xff1a; unordered_set 和 unordered_map的比较&#xff1a; 1. 核心区别 2. 使用场景 3. 在本题中的选择 4. 性能对比 5. 成员函数差异 unordered_table.begin()函数是返回的键…

国标渠道研究:专业为渠道策略提供数据支持(渠道调研)

北京国标市场调查有限公司是一家专业的市场调查公司&#xff0c;&#xff08;线上问卷调查&#xff09;&#xff08;第三方市场咨询&#xff09;&#xff08;消费者调查研究&#xff09;专注于为企业提供全方位的渠道研究服务。服务范围包括渠道策略研究、渠道销售数据分析和渠…

深入理解 C 语言中的拷贝函数

目录1. C 语言中的主要拷贝函数2. strcpy&#xff1a;字符串拷贝函数签名示例局限性3. strncpy&#xff1a;指定长度的字符串拷贝函数签名示例局限性4. memcpy&#xff1a;通用内存拷贝函数签名示例优势局限性5. memmove&#xff1a;支持重叠内存拷贝函数签名示例优势局限性6. …

主数据变更流程

主数据&#xff08;如客户、供应商、产品等&#xff09;的变更流程&#xff08;新增、更新、停用等&#xff09;是主数据管理&#xff08;MDM&#xff09;的核心环节&#xff0c;其设计需兼顾数据质量&#xff08;准确性、一致性&#xff09;、业务合规&#xff08;审批权限、审…

VUE2 学习笔记 合集

​​​​​​​VUE2 学习笔记1 VUE特点、开发者工具、入门Demo-CSDN博客 VUE2 学习笔记2 数据绑定、数据代理、MVVM_vue2的数据绑定-CSDN博客 VUE2 学习笔记3 v-on、事件修饰符、键盘事件_vue2组件 点击事件-CSDN博客 VU2 学习笔记4 计算属性、监视属性-CSDN博客 VUE2 学习…