Java多线程与线程池技术详解(四)
接受失败:“失败是什么?没有什么,只是更走近成功一步;成功是什么?就是走过了所有通向失败的路,只剩下一条路,那就是成功的路。”这句话很好地诠释了如何看待失败的问题,即每一次跌倒都是通往胜利道路上不可或缺的一部分。
创造机会:“不要等待机会,而要创造机会。”这句话鼓励人们主动出击,不要总是期待外界给予完美的条件或时机,而是要勇于尝试,创造属于自己的机遇。
目录
上一篇博客课后习题
编写一个简单的生产者-消费者模式程序
实现一个多阶段流水线作业
设计一个支持动态调整线程数量的线程池框架
分析并修复一段包含潜在死锁风险的代码片段
探索LockSupport.park()和unpark()的用法
第4章 线程池入门
4.1 ThreadPoolExecutor
4.1.1 创建线程池
4.1.2 关闭线程池
4.2 Executor接口
4.3 ExecutorService 接口
4.3.1 Callable返回任务执行结果
4.3.2 .shutdown与shutdownNow
4.4 Executors 工具箱
4.5 线程工厂与线程组
4.6 线程池异常处理
4.7 本章习题
上一篇博客课后习题
编写一个简单的生产者-消费者模式程序
根据提供的资料,我们可以创建一个使用java.util.concurrent包中工具来实现生产者-消费者模式的例子。这里我们将采用BlockingQueue接口的一个具体实现如ArrayBlockingQueue作为缓冲区。该队列允许我们利用其内置的方法put()和take()来进行阻塞操作,确保当队列满时生产者会被阻塞,而当队列为空时消费者也会被阻塞等待元素出现。下面是一个简化的代码示例:
import java.util.concurrent.*;public class ProducerConsumerExample {private static final int BUFFER_SIZE = 10;private static final BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(BUFFER_SIZE);public static void main(String[] args) throws InterruptedException {Thread producer = new Thread(() -> {try {for (int i = 0; ; i++) {System.out.println("Producing item: " + i);queue.put(i); // 如果队列已满,则此方法会自动阻塞直到有空间可用System.out.println("Buffer size after production: " + queue.size());Thread.sleep(100); // 模拟生产时间}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});Thread consumer = new Thread(() -> {try {while (true) {Integer item = queue.take(); // 如果队列为空,则此方法会自动阻塞直到有元素可取System.out.println("Consuming item: " + item);System.out.println("Buffer size after consumption: " + queue.size());Thread.sleep(150); // 模拟消费时间}} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producer.start();consumer.start();producer.join();consumer.join();} }
实现一个多阶段流水线作业
对于多阶段流水线作业,可以考虑使用java.util.concurrent.Phaser或自定义信号量机制来同步各个阶段之间的执行。每个阶段的任务完成之后通知下一个阶段开始工作。下面给出的是一个简化版本,其中每个阶段都是通过独立线程完成,并且通过共享变量传递数据给下一级别处理。
class PipelineStage implements Runnable {private final Phaser phaser;private final String name;private final Object input;private final Consumer<Object> output;public PipelineStage(Phaser phaser, String name, Object input, Consumer<Object> output) {this.phaser = phaser;this.name = name;this.input = input;this.output = output;}@Overridepublic void run() {phaser.arriveAndAwaitAdvance(); // 等待所有前驱阶段完成System.out.println(name + " processing...");// 模拟处理过程...try { Thread.sleep((long)(Math.random() * 500)); } catch (InterruptedException e) {}if (output != null) output.accept(input); // 将结果传递给下一阶段phaser.arriveAndDeregister(); // 完成本阶段后注销} }// 测试用例 public class MultiStagePipeline {public static void main(String[] args) throws InterruptedException {Phaser phaser = new Phaser();phaser.register(); // 注册主线程// 创建多个阶段并启动它们PipelineStage stage1 = new PipelineStage(phaser, "Stage 1", "Input Data", null);PipelineStage stage2 = new PipelineStage(phaser, "Stage 2", stage1, null);PipelineStage stage3 = new PipelineStage(phaser, "Stage 3", stage2, result -> System.out.println("Final Output: " + result));new Thread(stage1).start();new Thread(stage2).start();new Thread(stage3).start();phaser.arriveAndAwaitAdvance(); // 等待所有阶段完成} }
设计一个支持动态调整线程数量的线程池框架
要构建这样一个线程池,我们需要考虑如何监控当前的工作负载并根据需要调整线程的数量。可以通过监听器模式或者轮询的方式来检测任务队列的状态,并相应地增加或减少线程数以优化资源利用率。此外,还需要提供API让用户能够配置核心线程数、最大线程数及队列容量等参数,并允许这些设置在运行时动态更改。
import java.util.concurrent.*; import java.util.function.Consumer;public class DynamicThreadPoolExecutor extends ThreadPoolExecutor {private final Consumer<DynamicThreadPoolExecutor> configChangeListener;public DynamicThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,BlockingQueue<Runnable> workQueue, Consumer<DynamicThreadPoolExecutor> listener) {super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);this.configChangeListener = listener;}public synchronized void setCorePoolSize(int corePoolSize) {super.setCorePoolSize(corePoolSize);notifyConfigChange();}public synchronized void setMaximumPoolSize(int maximumPoolSize) {super.setMaximumPoolSize(maximumPoolSize);notifyConfigChange();}private void notifyConfigChange() {if (configChangeListener != null) {configChangeListener.accept(this);}}// 其他必要的方法... }
分析并修复一段包含潜在死锁风险的代码片段
假设有一段代码如下所示,它展示了两个线程分别试图获取对方持有的锁,从而可能导致死锁的情况。
public class DeadlockExample {private static final Object lock1 = new Object();private static final Object lock2 = new Object();public static void main(String[] args) {Thread t1 = new Thread(() -> {synchronized (lock1) {System.out.println("Thread 1: Holding lock 1...");try { Thread.sleep(100); } catch (InterruptedException e) {}synchronized (lock2) {System.out.println("Thread 1: Holding lock 1 & 2...");}}});Thread t2 = new Thread(() -> {synchronized (lock2) {System.out.println("Thread 2: Holding lock 2...");try { Thread.sleep(100); } catch (InterruptedException e) {}synchronized (lock1) {System.out.println("Thread 2: Holding lock 2 & 1...");}}});t1.start();t2.start();} }
为了避免这种情况的发生,我们应该遵循一定的规则来保证所有的锁请求都按照相同的顺序进行。例如,在上面的例子中,我们可以修改代码使得两个线程总是先尝试获得lock1再尝试获得lock2。这样做可以防止形成循环等待链,进而避免死锁的发生。
探索LockSupport.park()和unpark()的用法
最后,关于LockSupport.park()和unpark(),这两个函数提供了非常低级别的线程阻塞/唤醒功能。它们不是基于对象监视器(monitor)而是直接作用于线程本身。这意味着你可以更灵活地控制哪个特定的线程应该被阻塞或唤醒。通常情况下,unpark(Thread thread)会在park()之前调用来“预存”一次许可,这样当目标线程调用park()时可以直接继续执行而不必等待其他线程显式地调用unpark()。此外,值得注意的是,即使多次调用了unpark(),只要有一次对应的park()调用就会消耗掉这个许可;如果再次调用park()而没有新的unpark()调用,则线程将重新进入阻塞状态。
第4章 线程池入门
4.1 ThreadPoolExecutor
4.1.1 创建线程池
在Java中,ThreadPoolExecutor是实现线程池的核心类之一。它允许开发者自定义线程池的行为,包括但不限于核心线程数、最大线程数、空闲线程存活时间等参数。通过这种方式,可以创建更加灵活且适合特定应用场景的线程池。
代码示例:
import java.util.concurrent.*;public class CustomThreadPoolExample {public static void main(String[] args) {// 定义一个简单的任务类class Task implements Runnable {private final String name;public Task(String name) {this.name = name;}@Overridepublic void run() {System.out.println("Executing task " + name);try {Thread.sleep(2000); // 模拟长时间运行的任务} catch (InterruptedException e) {// 如果线程被中断,则恢复中断状态Thread.currentThread().interrupt();System.err.println("Task " + name + " was interrupted.");}System.out.println("Task " + name + " completed.");}}// 创建自定义线程池int corePoolSize = 2; // 核心线程数int maximumPoolSize = 4; // 最大线程数long keepAliveTime = 5000; // 空闲线程存活时间(毫秒)TimeUnit unit = TimeUnit.MILLISECONDS;BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(10); // 任务队列容量为10ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 使用默认线程工厂RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy(); // 拒绝策略ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);// 提交多个任务给线程池执行for (int i = 1; i <= 6; i++) {executor.submit(new Task("Task-" + i));}// 关闭线程池...executor.shutdown();// 尝试优雅地关闭线程池,等待所有任务完成try {if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {System.out.println("Not all tasks have been completed within the timeout period.");}} catch (InterruptedException e) {Thread.currentThread().interrupt();}} }
这段代码展示了如何使用ThreadPoolExecutor来创建一个具有特定配置的线程池,并向其中提交若干个任务进行异步处理。注意这里选择了LinkedBlockingQueue作为任务队列,并设置了合理的大小以避免无限制的增长;同时指定了CallerRunsPolicy作为拒绝策略,这意味着当线程池无法接受新任务时,调用者所在的线程将会执行该任务。
4.1.2 关闭线程池
正确地关闭线程池非常重要,因为它不仅涉及到资源的有效释放,还可能影响到应用程序的整体性能和稳定性。根据需求的不同,可以选择调用shutdown()或shutdownNow()方法来停止线程池的工作。
shutdown():此方法会等待所有已提交的任务完成之后再终止线程池,但不再接受新的任务提交。shutdownNow():尝试立即停止所有正在执行中的任务,并返回未开始执行的任务列表。需要注意的是,这并不保证所有活动线程都能被成功中断。
此外,还可以结合awaitTermination()一起使用,以便在线程池完全结束前让程序等待一段时间。如果超出了指定的时间而线程池仍未关闭,则可以通过逻辑判断是否需要采取进一步措施。
代码补充:
// 在main方法末尾添加以下代码,确保线程池能够正常关闭 if (!executor.isTerminated()) {System.out.println("Shutting down Executor Service"); }// 或者使用更激进的方式,立即尝试关闭所有任务 List<Runnable> unfinishedTasks = executor.shutdownNow(); if (!unfinishedTasks.isEmpty()) {System.out.println("Unfinished tasks: " + unfinishedTasks.size()); }
4.2 Executor接口
Executor接口是最基础的执行器接口,它提供了一个简化了多线程编程的方式——将任务提交与任务执行分离出来。具体来说,它仅包含一个名为execute(Runnable command)的方法,用于接收实现了Runnable接口的对象,并安排它们在一个合适的线程上运行。
4.3 ExecutorService 接口
4.3.1 Callable返回任务执行结果
ExecutorService扩展了Executor接口的功能,增加了对Callable的支持,使得我们可以从非阻塞的任务中获取返回值。Callable类似于Runnable,但它允许抛出受检异常并且支持返回类型。为了得到Callable的结果,通常我们会使用submit()方法提交任务,并通过返回的Future对象查询结果或取消任务。
代码示例:
import java.util.concurrent.*;public class CallableExample {public static void main(String[] args) throws InterruptedException, ExecutionException {// 创建一个固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(2);// 定义一个有返回值的任务Callable<String> task = () -> {Thread.sleep(1000); // 模拟任务执行时间return "Hello from Callable!";};// 提交任务并获取Future对象Future<String> future = executor.submit(task);// 获取任务执行结果String result = future.get(); // 此处会阻塞直到任务完成System.out.println(result);// 关闭线程池executor.shutdown();} }
4.3.2 .shutdown与shutdownNow
如前所述,shutdown()方法可以让线程池进入“优雅关闭”状态,即不再接受新的任务,但是会继续处理已经提交的任务直到它们全部完成。相比之下,shutdownNow()则试图立即停止所有正在进行的任务,并清理掉尚未启动的任务。
4.4 Executors 工具箱
Executors是一个静态工具类,提供了几种常用的线程池创建方法。这些方法简化了线程池的初始化过程,让用户不必每次都手动设置复杂的构造参数。常见的有:
newCachedThreadPool():创建一个可根据需要动态调整大小的线程池,适用于执行大量短期生存期的任务。newFixedThreadPool(int nThreads):创建一个固定大小的线程池,适合于控制并发级别的情况。newSingleThreadExecutor():创建只有一个工作线程的线程池,确保所有任务按照顺序依次执行。newScheduledThreadPool(int corePoolSize):创建一个支持定时调度功能的线程池。newWorkStealingPool(int parallelism):创建一个工作窃取线程池,旨在提高多核处理器上的任务并行度。
代码示例:
import java.util.concurrent.*;public class ExecutorsExample {public static void main(String[] args) {// 创建不同类型的线程池ExecutorService cachedPool = Executors.newCachedThreadPool();ExecutorService fixedPool = Executors.newFixedThreadPool(3);ExecutorService singlePool = Executors.newSingleThreadExecutor();ScheduledExecutorService scheduledPool = Executors.newScheduledThreadPool(2);ExecutorService workStealingPool = Executors.newWorkStealingPool();// 提交任务给不同的线程池Runnable task = () -> System.out.println("Task executed by " + Thread.currentThread().getName());cachedPool.submit(task);fixedPool.submit(task);singlePool.submit(task);scheduledPool.schedule(task, 2, TimeUnit.SECONDS);workStealingPool.submit(task);// 关闭线程池cachedPool.shutdown();fixedPool.shutdown();singlePool.shutdown();scheduledPool.shutdown();workStealingPool.shutdown();} }
4.5 线程工厂与线程组
这部分内容涉及到了更底层的线程管理机制。线程工厂(ThreadFactory)接口允许我们自定义线程的创建方式,比如命名规则、优先级设定等。而线程组(ThreadGroup)则是用来组织相关线程的一种结构,在某些情况下可以帮助更好地管理和监控线程集合。
代码示例:
import java.util.concurrent.*;public class ThreadFactoryExample {public static void main(String[] args) {// 自定义线程工厂ThreadFactory customThreadFactory = runnable -> {Thread thread = new Thread(runnable, "CustomThread-" + Thread.activeCount());thread.setDaemon(true); // 设置为守护线程thread.setPriority(Thread.MAX_PRIORITY); // 设置最高优先级return thread;};// 使用自定义线程工厂创建线程池ExecutorService executor = Executors.newFixedThreadPool(2, customThreadFactory);// 提交任务Runnable task = () -> System.out.println("Running in " + Thread.currentThread().getName());executor.submit(task);// 关闭线程池executor.shutdown();} }
4.6 线程池异常处理
当线程池中的任务抛出未捕获的异常时,默认情况下JVM会打印堆栈跟踪信息并将线程标记为失败状态。为了避免这种情况,可以为每个线程设置一个UncaughtExceptionHandler,或者直接利用Future.get()捕获由Callable产生的异常。
代码示例:
import java.util.concurrent.*;public class ExceptionHandlingExample {public static void main(String[] args) {// 创建线程池并设置未捕获异常处理器ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);executor.setUncaughtExceptionHandler((t, e) -> System.err.println("Thread " + t.getName() + " threw exception: " + e.getMessage()));// 提交可能会抛出异常的任务executor.submit(() -> {throw new RuntimeException("Something went wrong!");});// 使用Future捕获Callable产生的异常Future<?> future = executor.submit(() -> {throw new Exception("Another issue occurred.");});try {future.get(); // 此处会抛出ExecutionException包装原始异常} catch (InterruptedException | ExecutionException e) {System.err.println("Caught exception from Future: " + e.getCause().getMessage());}// 关闭线程池executor.shutdown();} }
4.7 本章习题
请参照章节开头给出的例子和说明,尝试编写一些简单的练习来加深理解,例如实现生产者-消费者模式、构建多阶段流水线作业等。此外,也可以探索更多关于LockSupport.park()/unpark()的知识点,了解它们是如何帮助实现低级别的线程同步操作的。
相关文章:
Java多线程与线程池技术详解(四)
接受失败:“失败是什么?没有什么,只是更走近成功一步;成功是什么?就是走过了所有通向失败的路,只剩下一条路,那就是成功的路。”这句话很好地诠释了如何看待失败的问题,即每一次跌倒…...
树莓派开发笔记
一. 登录方式 1.1 方式一:HDMI视频线 1.2 方式二:串口 查看串口有否被加密,默认情况下树莓派串口和蓝牙连接,需先断开蓝牙连接,串口才能用于数据通信。 1.2.1 如何使用串口登录 打开SD卡根目录的"config.txt"文件,将以下内容添加在最后并且保存。这样就停止…...
【数据结构】遍历二叉树
遍历二叉树的算法描述(递归定义) 先序遍历 若二叉树为空,则空操作; 否则 (1)访问根节点 (2)先序遍历左子树 (3)先序遍历右子树 中序遍历 若二叉树为空…...
嵌入式蓝桥杯学习7 产生PWM
Cubemx配置 打开cubemx,前面的配置看上文,这里主要配置定时器产生PWM波。 以PA1的TIM2-CH2通道为例进行演示。 1.在Timers中打开TIM2,将Channel2配置为PWM Generation CH2。 2.将Clock Source 选择为Internal Clock。 3.配置Paramater Settings中的参…...
档案学实物
档案工作 档案工作的性质 服务性 文化性 管理性 政治性 科学性 档案工作的地位 档案工作的效益 社会性,隐蔽性,滞后性 档案工作的发展规律 档案收集 档案收集工作的内容意义 档案收集工作的具体要求 档案室的档案收集工作 档案馆的档案收集工作 档案…...
数据清洗代码:缺失值,异常值,离群值Matlab处理
目录 基本介绍程序设计参考资料基本介绍 一、过程概述 本过程适用于处理SCADA系统采集到的数据,以及具有类似需求的数据集。处理步骤包括缺失值处理、异常值处理和离群值处理,旨在提升数据质量,增强数据的相关性,同时保持数据的原始特征和随机性。 二、缺失值处理 对于SC…...
Windows设备go环境安装配置
一、下载go安装包 官网链接:All releases - The Go Programming Language (google.cn) 安装过程比较简单,这里不再赘述,可参考这位博主的文章。本文重点在环境配置。golang环境详细安装、配置_golang安装-CSDN博客 二、环境变量配置 1.添…...
导体、半导体和绝缘体
半导体可以根据不同的组合去改变电阻,所以可以用来制作芯片。...
shell 6 if条件判断与for循环结构 (泷羽sec)
声明 学习视频来自B站UP主 泷羽sec,如涉及侵泷羽sec权马上删除文章。 笔记只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 这节课旨在扩大自己在网络安全方面的知识面,了解网络安全领域的见闻,了…...
MetaGPT 安装
1. 创建环境 conda create -n metagpt python3.10 && conda activate metagpt2. 可编辑方式安装 git clone --depth 1 https://github.com/geekan/MetaGPT.git cd MetaGPT pip install -e .3. 配置 metagpt --init-config运行命令,在C盘位置C:\Users\325…...
论文阅读:Single-cell transcriptomics of 20 mouse organs creates a Tabula Muris
The Tabula Muris Consortium., Overall coordination., Logistical coordination. et al. Single-cell transcriptomics of 20 mouse organs creates a Tabula Muris. Nature 562, 367–372 (2018). 论文地址:https://doi.org/10.1038/s41586-018-0590-4 代码地址…...
图生3d 图生全景 学习笔记
目录 instantsplat Aluciddreamer ZoeDepth 会自动下载模型: 图生全景图SD-T2I-360PanoImage: instantsplat Sparse-view SfM-free Gaussian Splatting in Seconds 稀疏视图无SfM高斯喷洒 GitHub - NVlabs/InstantSplat: InstantSplat: Sparse-vi…...
分库分表—4.数据迁移系统文档
大纲 1.数据库设计 2.枚举类 3.接⼝设计 4.定时任务设计 (1)定时核对校验数据的定时任务 (2)数据量统计定时任务 (3)增量数据落地定时任务 (4)失败重试定时任务 5.技术亮点 (1)滚动拉取方案 (2)巧妙的统计滚动进度方案 (3)防止增量同步数据丢失和高效写入方案 (4)…...
HAMR技术进入云存储市场!
2024年12月3日,Seagate宣布其Mozaic 3系列HAMR(热辅助磁记录)硬盘获得了来自一家领先云服务提供商(可能AWS、Azure或Google Cloud其中之一)以及其他高容量硬盘客户的资格认证。 Seagate的Mozaic 3技术通过引入热辅助磁…...
Vulnhub---kioptirx5 超详细wp
个人博客 WuTongSec 欢迎大佬指点 打点 nmap 192.168.128.0/24 -sP 找ip nmap 192.168.128.137 --min-rate 10000 -p- 简单全端口扫描 nmap 192.168.128.137 -sC -sV -O -sT 详细 脚本 版本 系统 扫描 dirsearch -u http://192.168.128.137 目录扫描 PORT S…...
单片机状态机实现多个按键同时检测单击、多击、长按等操作
1.背景 在之前有个项目需要一个或多个按键检测:单击、双击、长按等操作 于是写了一份基于状态机的按键检测,分享一下思路 2.实现效果 单击翻转绿灯电平 双击翻转红灯电平 长按反转红绿灯电平 实现状态机检测按键单击,双击,长…...
oracle之用户的相关操作
(1)创建用户(sys用户下操作) 简单创建用户如下: CREATE USER username IDENTIFIED BY password; 如果需要自定义更多的信息,如用户使用的表空间等,可以使用如下: CREATE USER mall IDENTIFIED BY 12345…...
黑马redis
Redis的多IO线程只是用来处理网络请求的,对于读写操作命令Redis仍然使用单线程来处理 Redisson分布式锁实现15问 文章目录 主线程和IO线程是如何协作的Unix网络编程中的五种IO模型Linux世界一切皆文件生产上限制keys *、flushdb、flushall等危险命令keys * 遍历查询100W数据花…...
HCIA-Access V2.5_1_2 PON技术的特点、优势与典型应用
PON接入技术优势 它的接入方式有两种,点到点光接入和点到多点光接入。 点到点 PON口的资源被一个用户独占,该用户可以享受到更好的带宽体验,同时故障好排查,出现问题,重点检测这一条链路以及终端用户,同…...
css部分
前面我们学习了HTML,但是HTML仅仅只是做数据的显示,页面的样式比较简陋,用户体验度不高,所以需要通过CSS来完成对页面的修饰,CSS就是页面的装饰者,给页面化妆,让它更好看。 1 层叠样式表&#…...
铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...
渗透实战PortSwigger靶场:lab13存储型DOM XSS详解
进来是需要留言的,先用做简单的 html 标签测试 发现面的</h1>不见了 数据包中找到了一个loadCommentsWithVulnerableEscapeHtml.js 他是把用户输入的<>进行 html 编码,输入的<>当成字符串处理回显到页面中,看来只是把用户输…...
