Java大师成长计划之第16天:高级并发工具类
📢 友情提示:
本文由银河易创AI(https://ai.eaigx.com)平台gpt-4o-mini模型辅助创作完成,旨在提供灵感参考与技术分享,文中关键数据、代码与结论建议通过官方渠道验证。
在现代Java应用中,处理并发问题是确保系统性能和可扩展性的关键。在前面的学习中,我们已经了解了Java中的基本线程操作和线程安全机制。本篇文章将深入探讨Java的高级并发工具类,包括Executor框架、Future和Fork/Join框架,以帮助你更好地管理并发任务。
一. Executor框架
1.1 什么是Executor框架?
Executor框架是Java在java.util.concurrent
包中提供的一套用于管理并发任务的工具。它是基于生产者—消费者模式设计的,主要目的是通过线程池来有效管理线程的生命周期,简化线程的创建、管理和调度。与传统的创建和管理线程的方式不同,Executor框架让开发者不需要手动管理线程,而是通过提交任务来进行调度和执行。通过合理使用线程池,Executor框架能够显著提升应用程序的性能,减少线程的创建和销毁开销,避免资源的浪费。
在没有线程池的情况下,每次需要执行任务时都要手动创建线程,这会导致创建大量线程的开销和管理困难。而Executor框架提供了一种统一的方式来提交任务并执行,开发者只需关心任务的提交和管理,而不必关注具体的线程创建与销毁的细节。
1.2 Executor框架的核心接口
Executor框架主要由以下几种接口组成:
-
Executor接口:它是Executor框架的顶层接口,定义了一个方法
execute(Runnable command)
,用于提交一个Runnable任务。通过这个接口,线程池能够执行传递给它的任务。 -
ExecutorService接口:它继承了Executor接口,并添加了更多与任务生命周期相关的方法,比如任务的提交、任务的取消等。
ExecutorService
接口提供了更强大的功能,支持提交Callable
任务和获取任务的执行结果。它还包含了管理线程池生命周期的方法,如shutdown()
。 -
ScheduledExecutorService接口:它继承了
ExecutorService
接口,并提供了对定时任务和周期性任务的支持。开发者可以使用它调度任务在指定时间执行,或定期执行。
1.3 Executor的实现类
Java提供了多个Executor
接口的实现类,最常用的实现类有:
-
ThreadPoolExecutor:这是Executor框架中最强大且灵活的线程池实现类。它支持动态调整线程池的大小,可以根据需要创建和管理线程。
ThreadPoolExecutor
提供了丰富的配置选项,适合于大多数并发任务的管理。 -
ScheduledThreadPoolExecutor:这是
ScheduledExecutorService
的实现类,支持定时和周期性执行任务。它比Timer
类更加灵活,并能更好地处理多线程场景中的异常。 -
Executors:这是一个工厂类,提供了静态方法来创建不同类型的线程池,如固定大小线程池、单线程池和缓存线程池等。通过这个类,开发者能够更轻松地创建和配置线程池。
1.4 使用Executor框架创建线程池
Executor框架通过线程池来管理和调度任务。线程池的使用能够有效减少线程的创建和销毁开销,且能提供任务调度、执行、监控等功能。Java提供了一个工厂类Executors
,通过它可以快速创建不同类型的线程池。
1.4.1 创建固定大小线程池
import java.util.concurrent.*;public class ExecutorDemo {public static void main(String[] args) {// 创建一个固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(2);// 提交任务for (int i = 0; i < 5; i++) {executor.submit(() -> {System.out.println(Thread.currentThread().getName() + " is executing a task.");});}// 关闭线程池executor.shutdown();}
}
在这个例子中,我们创建了一个固定大小的线程池,池中的线程数为2。即使提交了5个任务,线程池中只有两个线程可以同时执行任务。任务的其余部分将被排队等待线程空闲。
1.4.2 创建单线程池
import java.util.concurrent.*;public class SingleThreadExecutorDemo {public static void main(String[] args) {// 创建一个只有一个线程的线程池ExecutorService executor = Executors.newSingleThreadExecutor();// 提交任务for (int i = 0; i < 5; i++) {executor.submit(() -> {System.out.println(Thread.currentThread().getName() + " is executing a task.");});}// 关闭线程池executor.shutdown();}
}
newSingleThreadExecutor()
方法创建一个只包含一个线程的线程池。这种类型的线程池常用于需要保证任务按顺序执行的场景,线程池中的任务会顺序执行,并且不会并行执行。
1.4.3 创建可缓存线程池
import java.util.concurrent.*;public class CachedThreadPoolDemo {public static void main(String[] args) {// 创建一个可缓存的线程池ExecutorService executor = Executors.newCachedThreadPool();// 提交任务for (int i = 0; i < 5; i++) {executor.submit(() -> {System.out.println(Thread.currentThread().getName() + " is executing a task.");});}// 关闭线程池executor.shutdown();}
}
newCachedThreadPool()
方法创建一个可缓存的线程池。线程池会根据任务的数量动态调整线程池的大小。如果有空闲线程,线程池会复用这些线程,否则会创建新线程来执行任务。当线程池中的线程长时间没有任务执行时,它们会被回收。
1.4.4 创建定时任务线程池
import java.util.concurrent.*;public class ScheduledExecutorServiceDemo {public static void main(String[] args) {// 创建一个定时任务线程池ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);// 提交定时任务:延迟1秒后执行executor.schedule(() -> {System.out.println(Thread.currentThread().getName() + " is executing a scheduled task.");}, 1, TimeUnit.SECONDS);// 提交周期性任务:每2秒执行一次executor.scheduleAtFixedRate(() -> {System.out.println(Thread.currentThread().getName() + " is executing a periodic task.");}, 0, 2, TimeUnit.SECONDS);}
}
newScheduledThreadPool()
方法用于创建一个可以执行定时任务和周期性任务的线程池。schedule()
方法用于提交延迟任务,而scheduleAtFixedRate()
方法用于提交周期性任务。
1.5 线程池的管理
线程池在执行任务时需要合理配置其参数,特别是线程池的大小、任务队列的类型、线程的最大空闲时间等。在使用线程池时,我们通常会面临以下几个问题:
-
线程池的大小:线程池的大小应根据系统的负载和任务的特点来合理配置。一般情况下,线程池的大小可以通过CPU核心数来确定。例如,
Runtime.getRuntime().availableProcessors()
方法可以返回当前系统的CPU核心数。对于I/O密集型任务,线程池可以配置为稍大于CPU核心数;而对于CPU密集型任务,线程池的大小通常不需要超过CPU核心数。 -
任务队列:线程池的任务队列用于存储等待执行的任务。常见的任务队列有:
- 无界队列(LinkedBlockingQueue):当线程池中的线程数达到最大值时,任务会被无限制地加入队列。
- 有界队列(ArrayBlockingQueue):有界队列限制了队列的大小,任务队列满时,新的任务将被拒绝。
- 优先级队列(PriorityBlockingQueue):任务会根据优先级进行排序。
-
拒绝策略:当线程池中的线程和任务队列都被占满时,可以选择任务的拒绝策略。常见的拒绝策略有:
- AbortPolicy:直接抛出异常(默认策略)。
- CallerRunsPolicy:由调用者线程来执行该任务。
- DiscardPolicy:直接丢弃任务。
- DiscardOldestPolicy:丢弃队列中最旧的任务。
ThreadPoolExecutor executor = new ThreadPoolExecutor(2, // corePoolSize4, // maximumPoolSize60, // keepAliveTimeTimeUnit.SECONDS, // time unitnew ArrayBlockingQueue<>(10), // work queuenew ThreadPoolExecutor.CallerRunsPolicy() // rejection policy
);
1.6 总结
Executor框架提供了一个非常强大而灵活的机制来管理并发任务。通过使用不同类型的线程池,开发者可以根据任务的特点,灵活地调度和执行任务。同时,Executor框架不仅简化了线程管理,也有效避免了手动管理线程池时的资源浪费和复杂性。随着你对线程池及其配置的不断熟悉,你将能够更好地应对多线程编程中的各种挑战。
二. Future接口
2.1 什么是Future?
Future
接口是Java中的一个重要接口,位于java.util.concurrent
包中,代表一个异步计算的结果。它提供了一种机制,使得开发者可以在任务执行完成后获取结果,同时还可以检查任务的完成状态或处理异常。Future
接口的设计使得多线程编程变得更加灵活和高效。
在并行编程中,通常会遇到需要在某个任务执行完成后获取其计算结果的场景。使用Future
接口,开发者不仅可以提交并行执行的任务,还可以在需要的时候安全地获取这些任务的结果或处理异常。
2.2 Future接口的主要方法
Future
接口定义了一些关键的方法,帮助开发者管理异步任务的执行。以下是Future接口
中最常用的方法:
-
boolean cancel(boolean mayInterruptIfRunning)
:尝试取消任务的执行。如果任务已被执行或已完成,则无法取消。mayInterruptIfRunning
参数指示是否中断正在执行的任务。 -
boolean isCancelled()
:检查任务是否已被取消。 -
boolean isDone()
:检查任务是否已完成。任务可能是通过正常完成、异常或被取消而完成。 -
V get()
throws InterruptedException, ExecutionException:获取任务的结果。如果任务尚未完成,该方法会阻塞,直到结果可用。 -
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException:获取任务的结果,并设置超时。如果在指定时间内未完成,则抛出TimeoutException
。
2.3 提交任务并获取结果
在Executor框架中,使用submit()
方法可以提交一个Callable
任务,并返回一个Future
对象。通过这个Future
对象,可以在任务执行完成后获取结果或处理异常。
示例:使用Future获取任务结果
import java.util.concurrent.*;public class FutureResultExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(1);// 提交一个Callable任务Future<Integer> future = executor.submit(() -> {// 模拟长时间任务Thread.sleep(2000);return 42; // 返回结果});// 在这里可以执行其他操作System.out.println("Task submitted, doing other things...");try {// 获取任务结果(阻塞式)Integer result = future.get(); // 这会等待任务完成System.out.println("Task result: " + result);} catch (InterruptedException | ExecutionException e) {e.printStackTrace();} finally {executor.shutdown(); // 关闭线程池}}
}
在这个示例中,我们提交了一个Callable
任务,计算结果的值为42。调用future.get()
时,如果任务未完成,当前线程会被阻塞,直到任务完成并返回结果。在这段时间内,我们仍然可以执行其他操作。
2.4 Future的常用用途
Future
接口可以用于多种场景,以下是一些典型的用途:
-
异步任务执行:
Future
非常适合于需要在后台线程中执行耗时操作的场景,比如文件下载、网络请求等。 -
批量处理:在需要处理大量数据时,可以使用
Future
提交多个异步任务,并在所有任务完成后获取结果。 -
任务取消:通过
Future.cancel()
方法,可以尝试取消正在执行的任务,这在处理长时间运行的操作时非常有用。 -
超时控制:使用
get(long timeout, TimeUnit unit)
方法,可以指定获取结果的超时时间,从而避免线程长时间阻塞。
2.5 示例:取消Future任务
import java.util.concurrent.*;public class CancelFutureExample {public static void main(String[] args) throws InterruptedException {ExecutorService executor = Executors.newFixedThreadPool(1);// 提交一个长时间运行的任务Future<Integer> future = executor.submit(() -> {try {Thread.sleep(5000); // 模拟长时间任务} catch (InterruptedException e) {System.out.println("Task was interrupted");return null; // 返回 null 表示任务中断}return 42; // 返回结果});// 等待一段时间后尝试取消任务Thread.sleep(1000);boolean canceled = future.cancel(true); // 请求取消System.out.println("Task canceled: " + canceled);try {// 尝试获取任务结果Integer result = future.get(); // 可能会抛出异常System.out.println("Task result: " + result);} catch (CancellationException e) {System.out.println("Task was canceled: " + e.getMessage());} catch (ExecutionException e) {System.out.println("Task encountered an exception: " + e.getCause());}executor.shutdown(); // 关闭线程池}
}
在这个示例中,我们提交了一个模拟长时间运行的任务。我们在1秒后尝试取消这个任务。调用future.cancel(true)
会请求取消任务,如果任务正在执行且可以中断,任务将在下一个检查点被中断。我们可以通过异常处理来捕获任务取消或执行中的异常。
2.6 总结
Future
接口为Java中的异步计算提供了强大的支持,允许开发者轻松管理和获取异步任务的结果。通过合理使用Future
,可以提高程序的响应能力和性能,特别是在处理耗时的操作或需要并发执行多个任务的场合。理解Future
的使用和特点,将使你在并发编程中游刃有余。
三. Fork/Join框架
3.1 什么是Fork/Join框架?
Fork/Join框架是Java 7引入的一种并行编程模型,旨在充分利用多核处理器的能力。该框架采用了分而治之的设计思想,将一个复杂的任务递归地分解成多个小任务并行执行,最终合并结果。Fork/Join框架位于java.util.concurrent
包中,主要由ForkJoinPool
、ForkJoinTask
及其子类RecursiveTask
和RecursiveAction
构成。
通过Fork/Join框架,开发者可以高效地处理需要大量计算的任务,特别是在处理大规模的数据集或计算问题时。由于其底层实现了工作窃取算法,因此它能够在任务执行过程中动态地调整线程的利用率,从而提高程序的执行效率。
3.2 ForkJoinPool
ForkJoinPool
是Fork/Join框架的核心组件,负责管理和调度Fork/Join任务。与传统的线程池不同,Fork/Join框架采用了工作窃取算法,这意味着空闲的工作线程可以从其他忙碌线程的任务队列中“窃取”任务以执行。这种设计极大地提高了多核CPU的利用率,避免了线程的长时间空闲。
3.2.1 ForkJoinPool的基本特性
- 工作窃取:每个工作线程都有一个双端队列,用于存储待处理的任务。当线程的任务队列为空时,它会从其他线程的队列中窃取任务执行。
- 分层结构:Fork/Join框架支持递归任务的分层结构,能够自动调整任务的分配和执行策略。
- 可调的并行度:通过设置并行度,开发者可以控制Fork/Join框架的性能表现,适应不同的应用场景。
3.3 ForkJoinTask
ForkJoinTask
是Fork/Join框架中的抽象类,表示可以在ForkJoinPool
中执行的任务。它是异步计算的基础,主要有两种具体的实现:
- RecursiveTask<V>:用于在任务执行后返回结果的子类,适合有结果返回的计算任务。
- RecursiveAction:用于不返回结果的子类,适合只执行操作的任务。
3.4 使用RecursiveTask进行任务分解
在Fork/Join框架中,通常使用RecursiveTask
来实现可分解的计算任务。开发者需要重写compute()
方法,在该方法中定义任务的分解逻辑和结果合并的过程。
示例:使用Fork/Join框架计算斐波那契数
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.ForkJoinPool;public class Fibonacci extends RecursiveTask<Integer> {private final int n;public Fibonacci(int n) {this.n = n;}@Overrideprotected Integer compute() {if (n <= 1) {return n;}// 将任务分解为两个子任务Fibonacci f1 = new Fibonacci(n - 1);Fibonacci f2 = new Fibonacci(n - 2);// 异步计算第一个子任务f1.fork();// 计算第二个子任务int resultF2 = f2.compute();// 等待第一个子任务完成并获取结果int resultF1 = f1.join();// 返回最终结果return resultF1 + resultF2;}public static void main(String[] args) {ForkJoinPool pool = new ForkJoinPool();int n = 10; // 计算第10个斐波那契数int result = pool.invoke(new Fibonacci(n)); // 提交任务System.out.println("Fibonacci of " + n + " is " + result);}
}
在这个例子中,我们实现了一个计算斐波那契数的RecursiveTask
。compute()
方法中,当输入参数n
小于等于1时,直接返回结果;否则,将任务分解为两个子任务,然后异步计算第一个子任务,最后计算第二个子任务,并合并结果。
3.4.1 任务分解与合并
Fork/Join框架的核心思想是“分而治之”,即将一个大任务分解为多个小任务并行处理。在执行compute()
时,开发者需要决定何时分解任务以及如何合并结果。
- 任务分解:通过递归地创建子任务,任务可以被逐步分解到足够小且易于计算的程度。
- 结果合并:使用
join()
方法等待子任务完成并获取结果,合并所有子任务的结果以得到最终的答案。
3.5 使用RecursiveAction进行并行操作
当任务不需要返回结果时,可以使用RecursiveAction
类。RecursiveAction
的使用方式与RecursiveTask
类似,但不涉及结果的返回。
示例:使用Fork/Join框架进行数组求和
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.ForkJoinPool;public class ArraySum extends RecursiveAction {private final int[] array;private final int start;private final int end;private static final int THRESHOLD = 10; // 阈值public ArraySum(int[] array, int start, int end) {this.array = array;this.start = start;this.end = end;}@Overrideprotected void compute() {if (end - start <= THRESHOLD) {// 直接计算小块的和int sum = 0;for (int i = start; i < end; i++) {sum += array[i];}System.out.println("Sum from " + start + " to " + end + " is: " + sum);} else {// 分解任务int mid = (start + end) / 2;ArraySum leftTask = new ArraySum(array, start, mid);ArraySum rightTask = new ArraySum(array, mid, end);invokeAll(leftTask, rightTask); // 同时执行两个子任务}}public static void main(String[] args) {int[] array = new int[100];for (int i = 0; i < array.length; i++) {array[i] = i + 1; // 填充数组}ForkJoinPool pool = new ForkJoinPool();pool.invoke(new ArraySum(array, 0, array.length)); // 提交任务}
}
在这个例子中,我们实现了一个RecursiveAction
来计算数组的和。通过设置一个阈值,当任务的大小小于等于THRESHOLD
时,直接计算和;否则,将任务分解为两个子任务并并行处理。
3.6 Fork/Join框架的优势
- 高效利用多核处理器:Fork/Join框架的工作窃取算法能够充分利用多核CPU的处理能力,使得任务执行更加高效。
- 简化并行编程:通过提供简单的API,Fork/Join框架最大限度地简化了并行编程的复杂性,允许开发者专注于任务的分解和合并。
- 动态调整任务:由于采用工作窃取算法,Fork/Join框架能够动态调整并发任务的执行,从而提高系统的响应能力和处理效率。
3.7 总结
Fork/Join框架为Java开发者提供了一种强大的工具,能够以简洁的方式实现高效的并行处理。通过合理使用ForkJoinPool
、RecursiveTask
和RecursiveAction
,开发者可以将复杂的计算任务分解为小任务并行执行,从而显著提高程序的性能和响应能力。掌握Fork/Join框架将使你在处理大规模计算问题时游刃有余,充分发挥多核处理器的优势。
四. 总结
在本篇文章中,我们深入探讨了Java中的高级并发工具类,包括Executor框架、Future接口和Fork/Join框架。通过合理使用这些工具,我们可以更高效地管理线程和并发任务,提高应用程序的性能和响应能力。随着对并发编程的深入理解,你将能够设计出更加高效和可靠的Java应用程序。
继续关注我们的Java大师成长计划,接下来的内容将为你带来更多有趣和实用的技术!
相关文章:
Java大师成长计划之第16天:高级并发工具类
📢 友情提示: 本文由银河易创AI(https://ai.eaigx.com)平台gpt-4o-mini模型辅助创作完成,旨在提供灵感参考与技术分享,文中关键数据、代码与结论建议通过官方渠道验证。 在现代Java应用中,处理并…...
【C/C++】C语⾔内存函数
C语言内存函数 1. memcpy使用和模拟实现 memcpy可以代替strcpy void * memcpy ( void * destination, const void * source, size_t num );//void*来接受任意指针,size_t 单位是字节 //memcpy的头文件为<string.h> mem是memory的缩写 是内存的意思功能: …...
SQL JOIN 关联条件和 where 条件的异同
Inner join 对于 inner join,条件写到 on 和 where 部分是一样的。 select count(1) from web_site join web_page on web_site_skwp_web_page_id where web_cityPleasant Hill and wp_access_date_sk1;输出 0select count(1)from web_site join web_page on web…...
kotlin 数据类
一 kotlin数据类与java普通类区别 Kotlin 的 data class 与 Java 中的普通类(POJO)相比,确实大大减少了样板代码(boilerplate),但它的优势不止于自动生成 getter/setter、copy()、equals()、toString()&am…...
云效 MCP Server:AI 驱动的研发协作新范式
作者:黄博文、李晔彬 云效 MCP Server 是什么? 云效 MCP(Model Context Protocol)是阿里云云效平台推出的模型上下文协议标准化接口系统,作为连接 AI 助手与 DevOps 平台的核心桥梁,通过模型上下文协议将…...
复合机器人案例启示:富唯智能如何以模块化创新引领工业自动化新标杆
在国产工业机器人加速突围的浪潮中,富唯智能复合机器人案例凭借其高精度焊接与智能控制技术,成为行业标杆。然而,随着制造业对柔性化、全场景协作需求的升级,复合机器人正从单一功能向多模态协同进化。作为这一领域的创新者&#…...
信息系统项目管理师-软考高级(软考高项)2025最新(十三)(1)
个人笔记整理---仅供参考 信息系统项目理师-软考高级(软考高项)2025最新(十三)(1)第十三章项目资源管理 13.0资源管理概述 13.1管理基础 团队发展阶段背下来 13.2项目资源管理过程 13.3规划资源管...
archlinux 详解系统层面
Arch Linux 深度解析:从设计哲学到系统架构 一、Arch Linux 概述:滚动发行的极客之选 Arch Linux 是一款以 滚动更新(Rolling Release) 为核心特性的 Linux 发行版,强调 轻量、灵活、高度可定制,旨在让用…...
⭐️⭐️⭐️【课时1:大模型是什么?】学习总结 ⭐️⭐️⭐️ for《大模型Clouder认证:基于百炼平台构建智能体应用》认证
一、学习目标 概要 通过学习《课时1:大模型是什么?》,全面了解大模型的基础概念、核心特点、发展脉络及阿里云在大模型领域的布局,为后续基于百炼平台构建智能体应用的实践操作打下坚实的理论基础。 具体目标列表 理解人工智能到大模型的演变逻辑,明确大模型在AI发展历…...
qxl显卡与spice模块笔记
1、qxl虚拟显卡设备创建QemuConsole,并保存在全局变量consoles链表中。 static void qxl_realize_primary(PCIDevice *dev, Error **errp) {PCIQXLDevice *qxl PCI_QXL(dev);VGACommonState *vga &qxl->vga;Error *local_err NULL;qxl_init_ramsize(qxl)…...
Rust 官方文档:人话版翻译指南
鉴于大部分翻译文档都不太会说人话,本专栏主要内容为 rust 程序设计语言、rust 参考手册、std 库 等官方文档的中译中。...
切比雪夫不等式专题习题解析
切比雪夫不等式专题习题解析 前言 本文为概率论习题集专栏的切比雪夫不等式专题习题解析,针对习题篇中的10道题目提供详细解答。希望通过这些解析帮助大家深入理解切比雪夫不等式的应用和意义。 一、基础概念题解析 习题1解析: 错误。切比雪夫不等式适用于任何具有有限方…...
LearnOpenGL01:创建项目
基于LearnOpenGL 相关链接: 工程搭建 hello window 环境 UBUNTU GLFW3.3:负责创建窗口处理输入 GLAD:根据不同操作系统加载不同的OPENGL函数实现 安装GLFW以及编译项 sudo apt update sudo apt install cmake build-essential libglfw3-…...
基于论文《大规模电动汽车充换电设施可调能力聚合评估与预测》开发者说明文档
real_data_model.m 开发者说明文档 脚本概述 本MATLAB脚本实现了基于论文《大规模电动汽车充换电设施可调能力聚合评估与预测》(鲍志远,胡泽春)中提出的预测模型和评估方法。脚本使用真实的充电数据、天气数据和分时电价数据,实现了LSTM与线性模型混合…...
优雅草星云智控系统产品发布会前瞻:SNMP协议全设备开启指南-优雅草卓伊凡
优雅草星云智控系统产品发布会前瞻:SNMP协议全设备开启指南-优雅草卓伊凡 一、发布会重磅预告 1.1 星云智控系统发布会详情 优雅草科技将于2024年5月15日在成都市双流区天府国际生物城会议中心举办”星云智控系统产品发布会“。作为优雅草科技CTO,卓伊…...
【Python】Pycharm中安装库可靠的方法
博主需要在pycharm中安装Python需要的库,发现可以通过两个方法,一个是在terminal中安装,如下图: 另一个,是通过软件包安装。 博主发现,保险起见,还是通过软件包安装会比较稳妥。博主遇见一个库&…...
探索Stream流:高效数据处理的秘密武器
不可变集合 stream流 Stream流的使用步骤: 先得到一条Stream流(流水线),并把数据放上去 使用中间方法对流水线上的数据进行操作 使用终结方法对流水线上的数据进行操作 Stream流的中间方法 注意1:中间方法࿰…...
Debezium RelationalSnapshotChangeEventSource详解
Debezium RelationalSnapshotChangeEventSource详解 1. 类的作用与功能 1.1 核心功能 RelationalSnapshotChangeEventSource是Debezium中用于关系型数据库快照的核心抽象类,主要负责: 数据快照:对数据库表进行全量数据快照模式捕获:捕获数据库表结构事务管理:确保快照过…...
Open CASCADE学习|实现裁剪操作
1. 引言 Open CASCADE (简称OCC) 是一个功能强大的开源几何建模内核,广泛应用于CAD/CAM/CAE领域。裁剪操作作为几何建模中的基础功能,在模型编辑、布尔运算、几何分析等方面有着重要作用。本文将全面探讨Open CASCADE中的裁剪操作实现原理、应用场景及具…...
Microsoft Azure DevOps针对Angular项目创建build版本的yaml
Azure DevOps针对Angular项目创建build版本的yaml,并通过变量控制相应job的执行与否。 注意事项:代码前面的空格是通过Tab控制的而不是通过Space控制的。 yaml文件中包含一下内容: 1. 自动触发build 通过指定code branch使提交到此代码库的…...
Navicat 17最新保姆级安装教程(附安装包+永久使用方法)
前言 Navicat Premium 是一套可创建多个连接的数据库开发工具,让你从单一应用程序中同时连接 MySQL、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL 和 SQLite 。它与 OceanBase 数据库及 Amazon RDS、Amazon Aurora、Amazon Redshift、Microsoft Azure、Orac…...
在 Kotlin 中什么是委托属性,简要说说其使用场景和原理
在 Kotlin 中,属性委托和类委托是两种通过 by 关键字实现的强大特性,它们通过“委托”机制将行为或实现逻辑委托给其他对象,从而实现代码的复用和解耦。 1 属性委托 定义: 允许把属性的 get 和 set 方法的具体实现委托给另一个对…...
[Windows] 东芝存储诊断工具1.30.8920(20170601)
[Windows] 东芝存储诊断工具 链接:https://pan.xunlei.com/s/VOPpMjGdWZOLceIjxLNiIsIEA1?pwduute# 适用型号 东芝消费类存储产品: 外置硬盘:Canvio 系列 内置硬盘:HDW****(E300 / N300 / P300 / S300 / V300 / X30…...
按位段拼接十六进制
需求: 给一组位段及对应的值,拼接出该十六进制值。 如, [15] : 0x1 [31:16] : 0xfafa [14:1] : 0x1af0 [0:0] : 0x1 def parse_range(range_str):"""解析位段字符串,返回高位和低位"""parts…...
FPGA 41 ,ICMP 协议详细解析之构建网络诊断系统( ICMP 协议与 IP 协议理论详细解析 )
目录 前言 一、ICMP协议介绍 1.1 ICMP协议介绍 1.2 ICMP报文格式 1.3 ICMP地位流程 1.4 为何需要ICMP差错报文 1.5 协议关系 二、FPGA 与 ICMP 2.1 平台选择与环境搭建 2.2 模块化设计 2.3 ICMP 功能设计 (1)ICMP 报文解析 (2&am…...
每天批次导入 100 万对账数据到 MySQL 时出现死锁
一、死锁原因及优化策略 1.1 死锁原因分析 批量插入事务过大: Spring Batch 默认将整个 chunk(批量数据块)作为一个事务提交,100 万数据可能导致事务过长,增加锁竞争。 并发写入冲突: 多个线程或批处理作…...
滑动窗口-窗口中的最大/小值-单调队列
求窗口的最大值 #include <iostream> //滑动窗口最大值用单调队列q[],q存储候选最大值的下标 //队列头是最大值的下标 using namespace std; const int N100010; int nums[N],q[N]; int hh0,tt-1;// hh 是队头指针,tt 是队尾指针,初始…...
Docker Compose 部署 MeiliSearch 指南
Docker Compose 部署 MeiliSearch 指南 目录 环境准备创建 MeiliSearch 配置文件启动 MeiliSearch 服务验证服务状态访问 MeiliSearch安全及防火墙设置...
在 MyBatis 中实现控制台输出 SQL 参数
在 MyBatis 中实现控制台输出 SQL 参数,可通过以下方案实现: # 一、使用 MyBatis-Plus 的 SqlLogInterceptor(推荐) 适用场景:项目已集成 MyBatis-Plus(3.5.3版本) 配置步骤ÿ…...
【MySQL】数据库、数据表的基本操作
个人主页:Guiat 归属专栏:MySQL 文章目录 1. MySQL基础命令1.1 连接MySQL1.2 基本命令概览 2. 数据库操作2.1 创建数据库2.2 查看数据库2.3 选择数据库2.4 修改数据库2.5 删除数据库2.6 数据库备份与恢复 3. 表操作基础3.1 创建表3.2 查看表信息3.3 创建…...
Java中的内部类详解
目录 什么是内部类? 生活中的内部类例子 为什么需要内部类? 生活中的例子 内部类的存在意义 内部类的分类 1. 成员内部类 什么是成员内部类? 成员内部类的特点 如何使用成员内部类? 成员内部类访问外部类同名成员 2. …...
【LangChain全栈开发指南】从LLM集成到智能体系统构建
目录 🌟 前言🏗️ 技术背景与价值💢 当前技术痛点🛠️ 解决方案概述👥 目标读者说明 🔍 一、技术原理剖析📊 核心概念图解💡 核心作用讲解🧩 关键技术模块说明⚖️ 技术选…...
《内存单位:解锁数字世界的“度量衡”》
🚀个人主页:BabyZZの秘密日记 📖收入专栏:C语言 🌍文章目入 一、基础单位:字节(Byte)二、进阶单位:千字节(KB)、兆字节(MB)…...
Spring Boot + MyBatis-Plus 高并发读写分离实战
引言 在高并发场景下,单一数据库实例往往成为性能瓶颈。数据库读写分离通过将读操作和写操作分配到不同的数据库实例,有效缓解主库压力,提升系统吞吐量。MyBatis-Plus 作为一款强大的持久层框架,结合 Spring Boot 能够轻松实现读…...
STC32G12K128-旋转编码器-软件去抖
STC32G12K128-旋转编码器-软件去抖 简介代码 简介 EC11旋转编码器是一种可以连续旋转的器件A,B,C为旋转编码引脚,带按键的有D,E引脚。引脚功能: A:编码器A相;B:编码器B相;C:公共端-一般接到GN…...
第J7周:对于ResNeXt-50算法的思考
目录 思考 一、代码功能分析 1. 构建 shortcut 分支(残差连接的旁路) 2. 主路径的第一层卷积(11) 4. 主路径的第三层卷积(11) 5. 残差连接 激活函数 二、问题分析总结:残差结构中通道数不一致的…...
古方焕新潮!李良济盒马联名养生水,以创新赋能中式养生新潮流
今天下午,中华老字号李良济与新零售巨头盒马联名的“五汁饮&暑清元气水”新品发布会,在李良济隆重举行。 新品发布会上,盒马与多家媒体齐聚李良济,通过中医文化体验、新品品鉴、生产全链路探秘、媒体采访等环节,不…...
使用PyTorch训练马里奥强化学习代理的完整指南
以下是使用PyTorch训练马里奥强化学习代理的完整指南,涵盖依赖库配置、环境搭建、核心代码实现及输出结果分析,结合关键优化策略与实战经验。 一、依赖库配置 基础环境安装 # 使用Anaconda创建虚拟环境(推荐) conda create -n m…...
STM32F103RCT6 + MFC实现网口设备搜索、修改IP、固件升级等功能
资源下载链接:https://download.csdn.net/download/qq_35831134/90712875?spm=1001.2014.3001.5501 一.大概逻辑: // 网口搜索大概逻辑: // ************************************************************************** // 一.环境: // 上位机用MFC下位机用STM32F103R…...
ch09 课堂参考代码
ch09 拓扑排序与基环树 拓扑排序 在一些场景中,需要完成一系列事情,这些事情之间有顺序关系或者依赖关系,在做一件事情之前必须先做另一件事,例如课程学习的先后顺序,这类问题可以抽象为图论中的拓扑排序问题。 拓扑…...
Day 15 训练
Day 15 对鸢尾花数据集进行处理,特征可视化,贝叶斯优化随机森林,Shap解释1. 导入必要的库2. 设置中文字体3. 加载数据集4. 查看数据5. 数据准备6. 贝叶斯优化随机森林7. 评估结果8. 绘制箱形图9. 绘制特征相关性热力图10. SHAP模型解释总结 对…...
Path to Integer_ABC402分析与解答
考虑怎么降低复杂度,使用分治策略降低搜索的复杂度。 对于a_i,j,其一定在最后结果数的第(2n-i-j)位(如果将最低位看成第0位),故将a_i,j看成a_i,j * 10^(2n-i-j),这样每次加上a_i,j就可以了。 从(1,1)到(n…...
嵌入式学习笔记 - 关于结构体成员地址对齐问题
一 在没有#pragma pack()这个宏声明的情况下 C语言中结构体成员分配内存大小时需要满足2个条件,这也是内存对齐的原则: ①每个成员变量的起始地址必须为其数据类型所占空间大小的整数倍 ②结构体所占空间总大小为其最大数据类…...
JAVA实战开源项目:健身房管理系统 (Vue+SpringBoot) 附源码
本文项目编号 T 180 ,文末自助获取源码 \color{red}{T180,文末自助获取源码} T180,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
升级element-ui步骤
1 执行 cnpm uninstall element-ui 删除element-ui依赖2 执行 cpm install element-ui -S 安装最新的element-ui,并加入到packjson中3 在element-ui中生成主题,并将主题文件加入到element-ui-theme中。删除所有旧版本到主题文件 *4 修改element-ui-theme…...
Dp通用套路(闫式)
闫式dp分析法: 从集合角度来分析DP问题。 核心思想: DP是一种求有限集中的最值或者个数问题 由于集合中元素的数量都是指数级别的,直接用定义去求,把每种方案都用dfs暴力枚举一遍,时间复杂度很高,此时用…...
如何删除豆包本地大模型
由于无法选择大模型的安装位置,因此会占用C盘大量空间,然后又找到不卸载的地方,经排查豆包大模型安装位为:C:\Users\[当前电脑用户]\AppData\Local\Doubao\User Data,只能进行手动卸载。...
在ISOLAR A/B 工具使用UDS 0x14服务清除单个DTC故障的配置
在ISOLAR A/B 工具使用UDS 0x14服务清除单个DTC故障的配置如下图所示 将DemClearDTCLimitation参数改成DEM_ALL_SUPPORTED_DTCS 此时0x14 服务就可以支持单个DTC的故障清除, 如果配置成 DEM_ONLY_CLEAR_ALL_DTCS 则只能够用0x14服务清楚所有DTC。...
Linux59 SSH配置前瞻 JumpServer双网卡ping通
为什么Ping这个IP地址Ping得通 本地址 [rootlocalhost network-scripts]# cat ifcfg-ens33 iTYPEEthernet BOOTPROTOnone DEFROUTEyes DEVICEens33 ONBOOTno IPADDR192.168.235.4 NETMASK255.255.255.0 GATEWAY192.168.235.2 DNS1114.114.114.114 [rootlocalhost network-scrip…...
TensorFlow中数据集的创建
目录 前言示例示例1示例2示例3示例4 前言 TensorFlow 的 tf.data.Dataset API 提供了一种灵活且高效的方式来加载和预处理数据。它可以轻松处理大规模数据集,并支持多种数据源格式。 所有数据集相关的内容都在tf.data中,from_tensor_slices:…...