CyclicBarrier 基本用法
CyclicBarrier 基本用法
简介
CyclicBarrier 是 Java 并发包(java.util.concurrent)中的一个同步辅助类。它允许一组线程相互等待,直到到达某个公共屏障点(common barrier point)。只有当所有参与的线程都到达屏障点时,这些线程才能继续执行。这与CountDownLatch不同,后者是一次性的,而CyclicBarrier可以在等待的线程被释放后重新使用。
使用场景
多线程任务中,让多个线程在某个特定的点上同步,确保完成所有线程都完成某个阶段后,再一起进入下一阶段。
比如:一个计算任务被分成了多个部分,每个部分由不同的线程进行处理,处理完成后需要汇总结果,这时候需要所有线程都完成计算后,才能进行汇总。
基本用法
创建 CyclicBarrier
使用 new CyclicBarrier(int parties) 创建一个新的 CyclicBarrier,其中 parties 参数指定了必须调用 await() 方法以使所有线程都能通过屏障的线程数量。
也可以提供第二个参数,这是一个 Runnable,当最后一个线程到达屏障时会执行这个Runnable,这可以用于在所有线程到达屏障之前执行一些特定的操作。
线程中使用 await() 方法
每个线程在需要等待其他线程的地方调用 await() 方法。该方法会挂起当前线程,直到所有线程都调用了 await() 方法。
如果当前线程不是最后一个到达屏障的线程,await() 将阻塞直到所有线程都到达。如果当前线程是最后一个到达的,则所有线程都会被唤醒继续执行。
重置屏障
可以通过调用 reset() 方法来重置 CyclicBarrier,这将导致所有等待的线程收到一个 BrokenBarrierException 异常,并且屏障计数会被重置为其初始状态。
示例
说明:
使用休眠函数模拟实际业务执行的耗时,使用线程池多线程的执行任务,所有任务完成后,汇总计算结果。
公共代码
给出模拟函数,以及线程池定义等前置条件代码。
package com.ysx.utils.concurrent;import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.security.SecureRandom;
import java.util.Map;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;public class CyclicBarrierTest {private static final Logger LOGGER = LoggerFactory.getLogger(CyclicBarrierTest.class);// 使用map模拟所有的数据,每个线程占据一个keyprivate final Map<Integer, Integer> countMap = new ConcurrentHashMap<>();// 核心线程数private static final int CORE_POOL_SIZE = 5;// 线程池private static final ExecutorService THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, CORE_POOL_SIZE * 2,10, TimeUnit.SECONDS, new LinkedBlockingDeque<>(1000));/*** 使用一个休眠函数,模拟实际业务的计算,并且等待其他线程的结束** @param cyclicBarrier 屏障独显* @param index 数据的key,这里用index表示*/private void calculate(CyclicBarrier cyclicBarrier, int index) {SecureRandom secureRandom = new SecureRandom();// 随机休眠时间,并作为数据值int randomSleepSeconds = secureRandom.nextInt(10);LOGGER.info("<{}> index: {}, randomSleepSeconds: {}.", Thread.currentThread().getName(), index, randomSleepSeconds);// 休眠,模拟线程计算耗时try {Thread.sleep(randomSleepSeconds * 1000);} catch (InterruptedException e) {throw new RuntimeException(e);}// 记录计算结果countMap.put(index, randomSleepSeconds);// 等待其他线程到达这个点LOGGER.info("<{}> index: {}, waiting other thread.", Thread.currentThread().getName(), index);try {cyclicBarrier.await();} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);}// 通过了这个屏障LOGGER.info("<{}> index: {}, has passed barrier.", Thread.currentThread().getName(), index);}}
场景1 基本用法
任务数量不超过线程池的核心线程数
@Test
@DisplayName("基本用法:任务数量不超过线程池的核心线程数")
public void test1() {int taskNum = 3;int threadNum = Math.min(CORE_POOL_SIZE, taskNum);// 这里 CyclicBarrier 的构造函数的参数 parties 表示需要拦截的线程的数量,示例中有3个子线程,1个主线程CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum + 1);for (int i = 0; i < threadNum; i++) {final int index = i;THREAD_POOL_EXECUTOR.execute(() -> calculate(cyclicBarrier, index));}try {// 等待所有子线程任务执行完成,超时时间为1分钟LOGGER.info("waiting all thread.");cyclicBarrier.await(1, TimeUnit.MINUTES);LOGGER.info("<{}> has passed barrier.", Thread.currentThread().getName());} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);} catch (TimeoutException e) {throw new RuntimeException(e);}LOGGER.info("finish calculate.");int sum = countMap.values().stream().mapToInt(Integer::intValue).sum();LOGGER.info("sum: {}.", sum);
}
运行后日志打印参考:(日志打印忽略时间戳)
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:105 - waiting all thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-3> index: 2, randomSleepSeconds: 7.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-1> index: 0, randomSleepSeconds: 7.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-2> index: 1, randomSleepSeconds: 7.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-2> index: 1, waiting other thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-3> index: 2, waiting other thread.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-1> index: 0, waiting other thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-3> index: 2, has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:108 - <main> has passed barrier.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-1> index: 0, has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:116 - finish calculate.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-2> index: 1, has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:118 - sum: 21.
日志说明:
- 有3个任务,分别用3个子线程执行,主线程调用
cyclicBarrier.await(1, TimeUnit.MINUTES);
方法,表示等待子线程任务执行完成,之后汇总结果。
场景2 构造函数中指定Runnable
构造函数Runnable的用法:该Runnable优先级高
@Test
@DisplayName("构造函数Runnable的用法:该Runnable优先级高")
public void test2() {int taskNum = 3;int threadNum = Math.min(CORE_POOL_SIZE, taskNum);// 这里 CyclicBarrier 的构造函数的参数 parties 表示需要拦截的线程的数量,示例中有3个子线程,1个主线程CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum + 1, new Runnable() {@Overridepublic void run() {LOGGER.info("<{}> is first priority.", Thread.currentThread().getName());}});for (int i = 0; i < threadNum; i++) {final int index = i;THREAD_POOL_EXECUTOR.execute(() -> calculate(cyclicBarrier, index));}try {// 等待所有子线程任务执行完成,超时时间为1分钟LOGGER.info("waiting all thread.");cyclicBarrier.await(1, TimeUnit.MINUTES);LOGGER.info("<{}> has passed barrier.", Thread.currentThread().getName());} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);} catch (TimeoutException e) {throw new RuntimeException(e);}LOGGER.info("finish calculate.");int sum = countMap.values().stream().mapToInt(Integer::intValue).sum();LOGGER.info("sum: {}.", sum);
}
打印日志参考:
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:139 - waiting all thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-3> index: 2, randomSleepSeconds: 9.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-2> index: 1, randomSleepSeconds: 7.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-1> index: 0, randomSleepSeconds: 6.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-1> index: 0, waiting other thread.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-2> index: 1, waiting other thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-3> index: 2, waiting other thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:130 - <pool-2-thread-3> is first priority.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-1> index: 0, has passed barrier.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-2> index: 1, has passed barrier.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-3> index: 2, has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:142 - <main> has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:150 - finish calculate.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:152 - sum: 22.
日志说明:
- 即构造函数的Runnable的优先级最高,在其他所有到达屏障点之后,这个线程的代码最先执行。
场景3 通用场景:分批处理
使用线程池处理的场景,由于线程池数量是有限的,所以一次并发执行的线程数是有上限的,比如为5,当总任务数为13时,就需要把任务分批处理,以线程池核心线程数量分批,13个任务和分为3批,每个批次分别为5,5,3个任务。在所有批次执行完成之后,再汇总所有的数据。
分批场景需要考虑最后一批的执行,最后一批的数量可能存在小于核心线程数量的情况,要以实际的数量为准。
参考代码如下:
@Test
@DisplayName("通用用法:任务数量存在超过线程池的核心线程数的场景,需要分批处理")
public void test3() {int taskNum = 13;// 计算分批计算的批次:任务数/核心线程数,并向上取整int batchNum = (int) Math.ceil((double) taskNum / CORE_POOL_SIZE);for (int batchIndex = 0; batchIndex < batchNum; batchIndex++) {int threadNum = CORE_POOL_SIZE;if (batchIndex == batchNum - 1) {// 如果是最后一批,需要以实际剩余的任务数作为线程数threadNum = taskNum - batchIndex * CORE_POOL_SIZE;}LOGGER.info("batch calculate, batchIndex: {}, threadNum: {}.", batchIndex, threadNum);// 这里 CyclicBarrier 的构造函数的参数 parties 表示需要拦截的线程的数量,这里有threadNum个子线程,1个主线程CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum + 1);for (int threadIndex = 0; threadIndex < threadNum; threadIndex++) {// 当前数据的index需要单独计数final int index = threadIndex + batchIndex * CORE_POOL_SIZE;THREAD_POOL_EXECUTOR.execute(() -> calculate(cyclicBarrier, index));}try {// 当前批次,等待所有子线程任务执行完成,超时时间为1分钟LOGGER.info("waiting all thread in this batch, batchIndex: {}.", batchIndex);cyclicBarrier.await(1, TimeUnit.MINUTES);LOGGER.info("<{}> has passed barrier in this batch, batchIndex: {}.", Thread.currentThread().getName(), batchIndex);} catch (InterruptedException e) {throw new RuntimeException(e);} catch (BrokenBarrierException e) {throw new RuntimeException(e);} catch (TimeoutException e) {throw new RuntimeException(e);}}LOGGER.info("finish calculate.");int sum = countMap.values().stream().mapToInt(Integer::intValue).sum();LOGGER.info("sum: {}.", sum);
}
参考日志:
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:168 - batch calculate, batchIndex: 0, threadNum: 5.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:178 - waiting all thread in this batch, batchIndex: 0.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-1> index: 0, randomSleepSeconds: 3.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-3> index: 2, randomSleepSeconds: 8.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-5> index: 4, randomSleepSeconds: 8.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-4> index: 3, randomSleepSeconds: 8.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-2> index: 1, randomSleepSeconds: 7.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-1> index: 0, waiting other thread.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-2> index: 1, waiting other thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-3> index: 2, waiting other thread.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-5> index: 4, waiting other thread.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-4> index: 3, waiting other thread.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:181 - <main> has passed barrier in this batch, batchIndex: 0.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:168 - batch calculate, batchIndex: 1, threadNum: 5.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:178 - waiting all thread in this batch, batchIndex: 1.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-1> index: 0, has passed barrier.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-1> index: 5, randomSleepSeconds: 8.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-2> index: 1, has passed barrier.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-3> index: 2, has passed barrier.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-3> index: 7, randomSleepSeconds: 8.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-2> index: 6, randomSleepSeconds: 8.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-5> index: 4, has passed barrier.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-5> index: 8, randomSleepSeconds: 5.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-4> index: 3, has passed barrier.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-4> index: 9, randomSleepSeconds: 3.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-4> index: 9, waiting other thread.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-5> index: 8, waiting other thread.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-2> index: 6, waiting other thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-3> index: 7, waiting other thread.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-1> index: 5, waiting other thread.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:181 - <main> has passed barrier in this batch, batchIndex: 1.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-4> index: 9, has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:168 - batch calculate, batchIndex: 2, threadNum: 3.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:178 - waiting all thread in this batch, batchIndex: 2.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-5> index: 8, has passed barrier.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-5> index: 10, randomSleepSeconds: 2.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-3> index: 7, has passed barrier.
[pool-2-thread-2] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-2> index: 6, has passed barrier.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-3> index: 12, randomSleepSeconds: 5.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:67 - <pool-2-thread-4> index: 11, randomSleepSeconds: 9.
[pool-2-thread-1] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-1> index: 5, has passed barrier.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-5> index: 10, waiting other thread.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-3> index: 12, waiting other thread.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:79 - <pool-2-thread-4> index: 11, waiting other thread.
[pool-2-thread-5] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-5> index: 10, has passed barrier.
[pool-2-thread-3] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-3> index: 12, has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:181 - <main> has passed barrier in this batch, batchIndex: 2.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:191 - finish calculate.
[pool-2-thread-4] INFO com.ysx.utils.concurrent.CyclicBarrierTest:88 - <pool-2-thread-4> index: 11, has passed barrier.
[main] INFO com.ysx.utils.concurrent.CyclicBarrierTest:193 - sum: 82.
日志说明:
- 分批处理,每个批次内部是并发执行的。
- 在所有批次执行完成之后,再汇总计算结果。
源代码地址
- github
- gitee
相关文章:
CyclicBarrier 基本用法
CyclicBarrier 基本用法 简介 CyclicBarrier 是 Java 并发包(java.util.concurrent)中的一个同步辅助类。它允许一组线程相互等待,直到到达某个公共屏障点(common barrier point)。只有当所有参与的线程都到达屏障点…...
限流、降级、熔断、隔离?
在微服务架构中,服务限流、降级、熔断和隔离是保障系统高可用性的核心手段,但它们解决的问题和应用场景不同。以下是它们的区别、解决方案和实际案例的详细说明: 一、服务限流(Rate Limiting) 定义:通过限…...
asm汇编源代码之-字库转换程序
将标准的16x16点阵汉字库(下载16x16汉字库)转换成适合VGA文本模式下显示的点阵汉字库 本程序需要调用file.asm中的子程序,所以连接时需要把file连接进来,如下 C:\> tlink chghzk file 调用参数描述如下 C:\> chghzk ; 无调用参数,转换标准库文件(SRC16.FNT)为适合VGA…...
深入浅出:信号灯与系统V信号灯的实现与应用
深入浅出:信号灯与系统V信号灯的实现与应用 信号灯(Semaphore)是一种同步机制,用于控制对共享资源的访问。在多线程或多进程环境下,信号灯能够帮助协调多个执行单元对共享资源的访问,确保数据一致性与程序…...
定时器介绍及简单应用
定时器介绍及简单应用 文章目录 定时器介绍及简单应用1.定时器基本介绍1.1MSP430的四种定时器: 2.定时器A(Timer_A)2.1特点2.2寄存器的命名2.3寄存器表格2.4计数器原理说明2.4.1时钟源、分频器、计数器、工作模式2.4.2计数器复位 2.5定时器中断2.5.1定时…...
运行一次性任务与定时任务
运行一次性任务与定时任务 文章目录 运行一次性任务与定时任务[toc]一、使用Job运行一次性任务1.创建一次性任务2.测试一次性任务3.删除Job 二、使用CronJob运行定时任务1.创建定时任务2.测试定时任务3.删除CronJob 一、使用Job运行一次性任务 1.创建一次性任务 (…...
TypeScript入门
个人简介 👀个人主页: 前端杂货铺 🙋♂️学习方向: 主攻前端方向,正逐渐往全干发展 📃个人状态: 研发工程师,现效力于中国工业软件事业 🚀人生格言: 积跬步…...
MySQL数据库备份与恢复详解
在数据库管理中,数据的备份与恢复是至关重要的一环。对于MySQL数据库,定期备份不仅能防止数据丢失,还能在发生故障时快速恢复数据库。本文将详细介绍MySQL数据库的备份与恢复方法,覆盖所有常用备份和恢复方式,帮助大家…...
【c语言】猜凶手
日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。 以下为4个嫌疑犯的供词: A说:不是我。 B说:是C。 C说:是D。 D说:C在胡说 已知3个人说了真话,1个人说的是假话。 现在请根据这些信…...
Java学习打卡-Day25-注解和反射、Class类
注解(JDK5引入) 什么是注解? Java注解(Annotation),也叫元数据。一种代码级别的说明,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面…...
【愚公系列】《Python网络爬虫从入门到精通》048-验证码识别(滑动拼图验证码)
🌟【技术大咖愚公搬代码:全栈专家的成长之路,你关注的宝藏博主在这里!】🌟 📣开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主! 👉 江湖人称"愚公搬代码",用七年如一日的精神深耕技术领域,以"…...
CMake中add_custom_target用法详解
在 CMake 中,add_custom_target 是一个用于创建自定义构建目标的命令。它主要用于定义一些不生成文件,但需要执行的特定操作(比如运行脚本、执行命令、触发其他构建步骤等)。以下是它的核心用途和特点: 基本语法 add_…...
埃隆·马斯克如何通过开源创新塑造未来
李升伟 编译 埃隆马斯克的名字在多个行业回响——从电动汽车、太空探索到人工智能及更多领域。虽然许多人关注他革命性的公司(如特斯拉、SpaceX、Neuralink和The Boring Company),但较少有人意识到他在开源软件运动中悄然却深远的影响力。本…...
大型语言模型中的工具调用(Function Calling)技术详解
一、引言 随着大型语言模型(LLM)能力的飞速发展,它们在自然语言理解、文本生成、对话交互等方面展现出了令人惊叹的表现。然而,LLM 本身并不具备执行外部操作的能力,比如访问网页、调用第三方 API、执行精确数学运算等…...
IKBC F108 白色背光普通版说明书
部分按键白色背光版和新的 RGB 版并不相同。比如灯光控制,新老款会有按键配置冲突的。 IKBC F108 白色背光款(普通款)按键说明 ScrLk 倒计时定时器 使用 F1~F12 及 1~9 控制时间,设置完成按 Enter 确认,或按 En…...
Microsoft Office 如何启用和正常播放 Flash 控件
对于新安装的 Office 默认是不支持启用 Flash 组件的,Flash 组件会无法播放或者黑屏。 本片文章就带你解决这个问题,相关资料都在下方连接内。前提概要,教程对应的版本是 mso16,即 Office 2016 及更新版本,以及 365 等…...
muduo库源码分析: One Loop Per Thread
One Loop Per Thread的含义就是,一个EventLoop和一个线程唯一绑定,和这个EventLoop有关的,被这个EventLoop管辖的一切操作都必须在这个EventLoop绑定线程中执行 1.在MainEventLoop中,负责新连接建立的操作都要在MainEventLoop线程…...
[ARC196A] Adjacent Delete 题解
假设 n n n 是偶数。如果我们忽略删除相邻数的条件,即可以任选两个数相减,那么答案应该是前 n 2 \frac{n}{2} 2n 大的数(记作“较大数”)的和减去前 n 2 \frac{n}{2} 2n 小的数(记作“较小数”)的和…...
拼团系统设计-人群标签的设计与思考
目录 轻量化人群标签数据采集与Redis BitMap应用 为什么需要人群标签? 设计思路:轻量化人群标签系统 1. 核心目标 2. 技术选型:Redis BitMap 3. 数据链路设计 技术实现:代码级拆解 1. 人群标签任务调度 2. 用户ID与BitMap索引映射…...
【Python] pip制作离线包
制作离线安装包是一种非常实用的方法,尤其是在网络环境受限或需要在多台机器上部署相同环境时。以下是详细的步骤,帮助您创建一个包含所有依赖项的离线安装包,并在后续环境中复用。 步骤 1:准备工具和环境 确保您有一台可以访问互…...
Java学习手册:Java异常处理机制
在Java编程中,异常处理是确保程序健壮性和稳定性的关键机制。异常是指程序运行过程中出现的错误或异常情况,如除以零、文件找不到或网络连接失败等。Java提供了强大的异常处理机制,帮助开发者捕获和处理这些异常情况,从而避免程序…...
[特殊字符] 第十二讲 | 地统计学基础与克里金插值法(Kriging)建模实践
📘 专栏:科研统计方法实战分享 | 地学/农学人的数据分析工具箱 ✍️ 作者:平常心0715 🗝️ 本讲关键词:Kriging、地统计学、变异函数、空间插值、空间预测、R语言 一、什么是地统计学? 地统计学࿰…...
Introducing Machine Learning with SAP Leonardo
Introducing Machine Learning with SAP Leonardo...
软考 系统架构设计师系列知识点之杂项集萃(49)
接前一篇文章:软考 系统架构设计师系列知识点之杂项集萃(48) 第76题 某文件管理系统在磁盘上建立了位视图(bitmap),记录磁盘的使用情况。若磁盘上物理块的编号依次为:0、1、2、……;…...
list容器
1. list 的介绍 list 是序列容器,允许在序列中的任何位置进行O(1)时间复杂度的插入和删除操作以及双向迭代。 list 容器实现为带头结点双向链表,双向链表可以将它们包含的每个元素存储在不同且不相关的存储位置。 2. list 的使用 2.1 构造函数 1.…...
Linux xorg-server 解析(一)- 编译安装Debug版本的xorg-server
一:下载代码 1. 配置源,以Ubuntu24.04 为例( /etc/apt/sources.list.d/ubuntu.sources): 2. apt source xserver-xorg-core 二:编译代码 1. sudo apt build-dep ./ 2. DEB_BUILD_OPTIONS="nostrip" DEB_CFLAGS_SET="-g -O0" dpkg-buildpac…...
VTK使用Render()渲染窗口的相关问题
转自个人博客:VTK使用Render()渲染窗口的相关问题 1. VTK更新数据但窗口不更新 问题:在对窗口内的数据进行更新后,VTK窗口不会立即更新,需要鼠标等交互后才会更新。 解决办法:对数据更新后,对VTK窗口也要…...
基于php的成绩分析和预警与预测网站(源码+lw+部署文档+讲解),源码可白嫖!
摘要 人类现已迈入二十一世纪,科学技术日新月异,经济、资讯等各方面都有了非常大的进步,尤其是资讯与网络技术的飞速发展,对政治、经济、军事、文化、教育等各方面都有了极大的影响。 利用电脑网络的这些便利,发展一套…...
文档检索技术详解 (Document Retriever)
一、文档检索的定义与核心概念 文档检索(Document Retriever)是一种信息检索技术,旨在从大量未结构化或半结构化文档中快速找到与特定查询相关的文档或信息。文档检索通常以在线(online)方式运行,能够实时…...
大模型SFT用chat版还是base版 SFT后灾难性遗忘怎么办
大模型SFT用chat版还是base版 进行 SFT 时,基座模型选用 Chat 还是 Base 模型? 选 Base 还是 Chat 模型,首先先熟悉 Base 和 Chat 是两种不同的大模型,它们在训练数据、应用场景和模型特性上有所区别。 在训练数据方面…...
【生活相关-日语-日本-东京-搬家后-瓦斯申请(2)-办理手续】
【生活相关-日语-日本-东京-搬家后-瓦斯申请(2)-办理手续】 1、前言2、情况说明(1)他人代办(2)打电话(3)网络申请(4)你将会面临什么,主要步骤&…...
matplotlib数据展示
目录 一、绘制直方图 1、简单直方图 2、绘制横向直方图 3、绘制堆叠直方图 4、对比直方图 二、折线图与散点图 三、绘制饼图 四、雷达图 1、简单雷达图 2、多层雷达图 五、总和 在前面的学习中,我们能够使用一些库进行数据的整合,收集&#x…...
三维激光测量助力企业检测效率提升3倍
智能制造与数字化浪潮席卷下,三维扫描技术已成为工业检测领域不可或缺的工具。面对传统检测手段的精度瓶颈与效率局限,三维扫描仪,以毫米级精度、非接触式测量与超高速扫描三大核心优势,为汽车制造、航空航天、消费电子等行业的品…...
基于RISC-V内核的嵌入式系统在机器人关节控制中的应用研究
摘要 随着机器人技术的飞速发展,关节控制作为机器人系统中的关键环节,对机器人的性能和稳定性起着至关重要的作用。传统的关节控制多采用基于ARM或DSP的嵌入式系统,但RISC-V架构的兴起为机器人关节控制提供了新的选择。本文结合多个基于RISC…...
斯库拉集团介绍
斯库拉集团有限公司坐落于世界自由贸易圣地,国际金融服务中心英属维京群岛BVI. 旗下有香港斯库拉集团(香港主板 上市公司),斯库拉环球国际控股集团 (香港主板上市企业),斯库拉国际贸易 有限公司(斯库拉集团有限公司),新加坡斯库拉集团有限公司,德国斯库拉集团有限公司,新西…...
运用instanceof判断Animal a是否为Dog类和是否为cat类
//Animal类(狗和猫的父类) public class Animal {private String color;private int age;public Animal(String color, int age) {this.color color;this.age age;}public Animal() {}public String getColor() {return color;}public void setColor…...
蓝桥杯嵌入式考前模块总结
一.RTC 使用RTC直接再cubeMX中配置启动时钟和日历 如第六届省赛 想要让RTC的秒每隔一秒递增1需要在时钟树界面观察RTC的主频 由于RTC时钟主频为32KHZ将异步预分频计数器的值设为31,将同步预分频计数器的值设为999这样就可以将RTC的时钟信号分频为1HZ达到1秒自增的…...
《汽车电器与电子技术》实验报告
SRS系统结构原理与故障检测诊断 车辆上为什么要配安全气囊?——解析汽车被动安全的关键防线 一、安全气囊的核心作用:应对高速碰撞的“救命缓冲垫” 车辆在高速碰撞时(如正面碰撞、侧面碰撞),人体会因惯性以极高速度…...
小刚说C语言刷题——第22讲 二维数组
昨天我们讲了一维数组,今天我们来讲二维数组。 1.定义 二维数组是指在数组名后跟两个方括号的数组。 2.语法格式 数据类型 数组名[下标][下标] 例如:int a[5][9];//表示5行9列的数组 3.访问二维数组元素 格式:数组名[行坐标][列坐标]…...
04--网络属性设置与多路复用
一、TCP可靠性分析 二、 scoket 属性设置 1、socket 属性设置表 NAMEgetsockopt, setsockopt - get and set options on sockets获取 和 设置 套接字属性 SYNOPSIS#include <sys/types.h> /* See NOTES */#include <sys/socket.h>int getsockopt(int so…...
AI大模型从0到1记录学习 day17
第 2 章 数据结构与算法基础 2.1 数据结构基础 2.1.1 什么是数据结构 数据结构是为了高效访问数据而设计出的一种数据的组织和存储方式。更具体的说,一个数据结构包含一个数据元素的集合、数据元素之间的关系以及访问和操作数据的方法。 像前面我们接触到的list、se…...
scanf函数功能与使用详解
【DeepSeek提问】 解释一下下面这段话: 函数scanf()是从标准输入流 stdin (标准输入设备, 一般指键盘)中读内容的通用子程序,可以按说明的格式读入多个字符,并保存在对应地址的变量中。 scanf函数返回成功读入的数据项数…...
使用Python从零开始构建端到端文本到图像 Transformer大模型
简介:通过特征向量从文本生成图像 回顾:多模态 Transformer 在使用Python从零实现一个端到端多模态 Transformer大模型中,我们调整了字符级 Transformer 以处理图像(通过 ResNet 特征)和文本提示,用于视觉…...
NDT和ICP构建点云地图 |【点云建图、Ubuntu、ROS】
### 本博客记录学习NDT,ICP构建点云地图的实验过程,参考的以下两篇博客: 无人驾驶汽车系统入门(十三)——正态分布变换(NDT)配准与无人车定位_settransformationepsilon-CSDN博客 PCL中点云配…...
第 1 篇✅ 用 AI 编程之前,你得先搞清楚你和 AI 是啥关系
程序员不是被替代的,是要学会主导 AI 的人 🧠 那些把 AI 当兄弟的程序员,后来都踩了坑 最近的一次线下开发者聚会,我们聊到“AI 编程”,现场笑声不断,也点醒了不少人。 有个朋友说: “我让 AI 写一个 Web 服务,它写得飞快,我一激动就上线了,结果上线后一堆坑,日志…...
Android Jetpack Compose 高级开发核心技术
Android Compose 高级技术总结 1. 性能优化 1.1 状态管理优化 状态提升原则:将状态提升到共享的最近共同父组件derivedStateOf:当需要基于多个状态计算派生状态时使用 val scrollState rememberScrollState() val showButton by remember {derivedS…...
Go小技巧易错点100例(二十五)
本期分享: 1. 使用atomic包实现无锁并发控制 2. Gin框架的中间件机制 3. 搞懂nil切片和空切片 使用atomic包实现无锁并发控制 sync/atomic包提供了原子操作,用于在多goroutine环境下安全地操作共享变量,避免使用锁带来的性能开销。 代码…...
如何用海伦公式快速判断点在直线的哪一侧
一、海伦公式的定义与推导 1. 海伦公式的定义 海伦公式(Heron’s Formula)是用于计算三角形面积的一种方法,适用于已知三角形三边长度的情况。公式如下: S s ( s − a ) ( s − b ) ( s − c ) S \sqrt{s(s - a)(s - b)(s - c…...
【异常处理】Clion IDE中cmake时头文件找不到 头文件飘红
如图所示是我的clion项目目录 我自定义的data_structure.h和func_declaration.h在unit_test.c中无法检索到 cmakelists.txt配置文件如下所示: cmake_minimum_required(VERSION 3.30) project(noc C) #设置头文件的目录 include_directories(${CMAKE_SOURCE_DIR}/…...
自动驾驶技术关键技术梳理
一、硬件 1、 传感器系统设计主要注意以下几个问题: 1.时间同步 一般包括多传感器之间时钟同源、帧同步触发的问题。首先要解决时钟同源问题,然后为了帧同步触发,可以让所有传感器整秒触发。常用GPS(最多分2路)给激光雷…...