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

Java类间变量共享与进度更新的实现策略

本文旨在探讨如何在Java中安全有效地共享和更新不同操作类别之间的变量值特别是在需要实时监控操作进度的场景中。我们将通过三种核心策略-观察者模式推动模型、轮询模式(拉模式)和基于多线程的共享状态管理——详细说明如何实现类间通信和数据同步并提供相应的代码示例和最佳实践建议。在Java应用程序开发中不同类别之间的数据交互是一种常见的需求。特别是在执行耗时的操作如文件复制和网络下载时我们通常需要在一个类别中执行任务并在另一个类别中实时显示或监控任务的进度。虽然通过静态变量直接访问是可行的但在多线程或复杂场景中可能会导致难以维护和调试的问题。本教程将讨论几个更强大、更专业的解决方案。1. 监控任务进度的挑战设想一个场景CopyFile 负责大文件的分块复制它将不断更新复制的数据量。而且 ProgressMonitor 此进度需要实时显示在用户界面或控制台上。核心挑战是CopyFile 如何通知更新后的进度值 ProgressMonitorProgressMonitor 如何获取到 CopyFile 最新进度如何在不紧密耦合两类的情况下实现这种通信如果 CopyFile 和 ProgressMonitor 在不同的线程中运行如何保证数据同步和线程安全下面我们将介绍三种主流实现策略。2. 策略1:观察者模式(推模型)观察者模式是一种行为设计模式它定义了对象之间的一对多依赖。当一个对象的状态发生变化时所有依赖它的对象都将被通知并自动更新。在这种模式下执行任务的类别Copy是“主题”Subject监控进度的类别Observer是“观察者”Observer。核心思想 Copy 类持有 Observer 每次进度更新时都会主动调用类实例 Observer 推动最新进度的方法。示例代码// Test.java - 主程序入口 public class Test { public static void main(String[] args) { // 创建观察者的例子 Observer observer new Observer(); // 创建复制任务的例子并将观察者注入 Copy copy new Copy(1000, observer); // 启动复制任务 copy.start(); } } // Observer.java - 进度观察者类 public class Observer { /** * 接收并显示进度更新 * param current 目前已完成的块数 * param total 总块数 */ public void updateProgress(int current, int total) { System.out.println(当前进度: current / total); } } // Copy.java - 文件复制任务类 public class Copy { public final int totalBlocks; // 总块数 private Observer observer; // 观察者实例 /** * 构造函数注入观察者 * param totalBlocks 文件总块数 * param observer 进度观察者 */ public Copy(int totalBlocks, Observer observer) { this.totalBlocks totalBlocks; this.observer observer; } /** * 复制启动文件模拟过程 */ public void start() { for (int current 1; current totalBlocks; current) { // 模拟耗时的操作 try { Thread.sleep(10); // 每次复制一小块数据 } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println(中断了复制过程。); return; } // 每次完成一个块通知观察者更新进度 observer.updateProgress(current, totalBlocks); } System.out.println(文件复制完成); return; } // 每次完成一个块通知观察者更新进度 observer.updateProgress(current, totalBlocks); } System.out.println(文件复制完成); } }优点实时性强 进度更新后立即通知观察者。职责分离 Copy 专注于复制逻辑Observer 专注于显示逻辑。低耦合 Copy 只需知道 Observer 有一个 updateProgress 方法不需要了解其内部实现。3. 策略二:轮询模式(拉模型)与观察者模式相反轮询模式不依赖于主动通知。在这种模式下监控进度的类别Observer会议定期主动执行任务类别Copy查询当前进度。核心思想 Observer 类持有 Copy 类的例子并在一个循环中不断调用 Copy 获得最新进展的方法。示例代码// Test.java - 主程序入口 public class Test { public static void main(String[] args) { // 创建复制任务的例子 Copy copy new Copy(1000); // 创建观察者实例并将复制任务注入 Observer observer new Observer(copy); // 启动观察者它将开始轮询进度 observer.start(); } } // Observer.java - 进度观察者类 public class Observer { private Copy copy; // 复制任务实例 /** * 构造函数注入复制任务 * param copy 复制任务实例 */ public Observer(Copy copy) { this.copy copy; } /** * 启动进度轮询 */ public void start() { System.out.println(开始监控文件复制进度...); while (copy.hasNextBlock()) { // 只要有未完成的块 // 模拟轮询间隔 try { Thread.sleep(100); // 每100毫秒查询一次进度 } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println(中断了进度监控。); return; } // 获取并显示当前进度 System.out.println(当前进度: copy.getCurrentBlock() / copy.totalBlocks); } System.out.println(文件复制完成(轮询确认)); } } // Copy.java - 文件复制任务类 public class Copy { public final int totalBlocks; // 总块数 private int currentBlock 0; // 目前已完成的块数 /** * 构造函数 * param totalBlocks 文件总块数 */ public Copy(int totalBlocks) { this.totalBlocks totalBlocks; // 在后台启动模拟复制过程的线程 new Thread(() - { for (int i 1; i totalBlocks; i) { try { Thread.sleep(20); // 模拟每次复制一小块数据的时间 } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println(中断了复制线程。); return; } currentBlock i; // 更新进度 } }).start(); } /** * 判断是否还有未完成的块 * return 若有未完成的块返回 true */ public boolean hasNextBlock() { return currentBlock totalBlocks; } /** * 获取目前已完成的块数 * return 目前已完成的块数 */ public int getCurrentBlock() { return currentBlock; } }优点控制权在观察者 观察者可以控制查询频率。实现相对简单 简单的状态共享不需要复杂的通知机制。缺点实时性稍差 根据轮询间隔进度更新可能会有延迟。资源消耗 频繁的轮询可能会导致不必要的CPU费用尤其是进度更新不频繁的时候。4. 策略3多线程共享状态与同步当 Copy 和 Observer 在不同的线程中运行时直接访问共享变量需要考虑线程安全。该策略结合了轮询的理念但更强调了多线程环境下的数据同步。核心思想 Copy 在单独的线程中执行任务并更新共享变量Observer 这个共享变量是在另一个线程中定期读取的。为了保证数据的可见性和一致性需要使用 volatile 关键字或更先进的同步机制。示例代码import java.util.concurrent.atomic.AtomicInteger; // Test.java - 主程序入口 public class Test { public static void main(String[] args) { // 创建共享进度对象 SharedProgress progress new SharedProgress(1000); // 创建并启动复制线程 Thread copyThread new Thread(new CopyTask(progress)); copyThread.setName(CopyThread); copyThread.start(); // 创建和启动观察者线程 Thread observerThread new Thread(new ProgressMonitor(progress)); observerThread.setName(ObserverThread); observerThread.start(); // 等待复制线程完成 try { copyThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println(主线程复制任务已完成。); } } // SharedProgress.java - 共享进度数据类 class SharedProgress { private final int totalBlocks; // 使用 AtomicInteger 保证原子操作或使用 volatile int currentBlock; // volatile 保证可见性但不能保证复合操作的原子性 private volatile int currentBlock 0; public SharedProgress(int totalBlocks) { this.totalBlocks totalBlocks; } public int getTotalBlocks() { return totalBlocks; } public int getCurrentBlock() { return currentBlock; } public void incrementProgress() { // 对于简单的自增操作volatile 你可以用适当的逻辑工作 // 但是如果需要更复杂的原子操作AtomicInteger 更安全 currentBlock; } public boolean isCompleted() { return currentBlock totalBlocks; } } // CopyTask.java - 拷贝任务在单独的线程中运行 class CopyTask implements Runnable { private SharedProgress progress; public CopyTask(SharedProgress progress) { this.progress progress; } Override public void run() { System.out.println(Thread.currentThread().getName() : 复制任务开始。); for (int i 0; i progress.getTotalBlocks(); i) { try { Thread.sleep(15); // 模拟复制每个数据的时间 } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println(Thread.currentThread().getName() : 中断了复制任务。); return; } progress.incrementProgress(); // 更新共享进度 } System.out.println(Thread.currentThread().getName() : 完成复制任务。); } } // ProgressMonitor.java - 进度监控器在单独的线程中运行 class ProgressMonitor implements Runnable { private SharedProgress progress; public ProgressMonitor(SharedProgress progress) { this.progress progress; } Override public void run() { System.out.println(Thread.currentThread().getName() : 进度监控开始。); while (!); while (!progress.isCompleted()) { try { Thread.sleep(80); // 每隔一段时间轮询进度进度 } catch (InterruptedException e) { Thread.currentThread().interrupt(); System.err.println(Thread.currentThread().getName() : 中断了进度监控。); return; } System.out.println(Thread.currentThread().getName() : 进度 progress.getCurrentBlock() / progress.getTotalBlocks()); } System.out.println(Thread.currentThread().getName() : 进度监控结束任务完成。); } }注意事项volatile 关键字 确保 currentBlock 变量的可见性。当线程修改时 currentBlock 当值时其他线程可以立即看到最新值而不是本地缓存的旧值。原子操作 如果 incrementProgress() 方法不仅仅是简单的 currentBlock但包含多个操作(例如) currentBlock currentBlock 1那么 volatile 不能保证其原子性。在这种情况下应该使用 java.util.concurrent.atomic 包中的类(如 AtomicInteger或 synchronized 关键字保护共享变量的访问。在上述示例中currentBlock 原子操作通常在JVM层面上进行但为了场景严谨复杂AtomicInteger 这是一种更安全的做法。线程管理 使用 Thread 类或 ExecutorService 管理线程生命周期。优雅退出 线程中断机制 (Thread.interrupt()) 建议停止线程而不是停止线程 Thread.stop()。5. 总结和最佳实践根据具体的应用场景和需求选择哪种策略观察者模式(推模型) 适用于需要实时和即时通知的场景生产者任务执行者希望主动通知消费者进度显示器。它提供了良好的解耦。轮询模式(拉模式) 适用于实时要求低或消费者想要控制获取频率的场景。实现相对简单但可能会有延迟和资源浪费。多线程共享状态 当任务和监控器必须在不同的线程中运行时这是一个不可避免的选择。通常需要正确处理线程安全性和数据可见性 volatile、synchronized 或 java.util.concurrent.atomic 包里的工具。通用建议解耦 尽量保持类之间的低耦合一个类不应过度依赖另一个类的内部实现细节。接口interface是实现解耦的有力工具。明确职责 每一类都要有明确单一的职责。错误处理 考虑任务中断、异常等情况并适当处理。并发考量 使用Java提供的并发工具和关键字始终优先考虑多线程环境中的线程安全。通过以上三种策略开发人员可以根据项目的具体需要灵活选择最合适的方式安全高效地分享Java中不同操作类别之间的变量和更新进度。

相关文章:

Java类间变量共享与进度更新的实现策略

本文旨在探讨如何在Java中安全有效地共享和更新不同操作类别之间的变量值,特别是在需要实时监控操作进度的场景中。我们将通过三种核心策略-观察者模式(推动模型)、轮询模式(拉模式)和基于多线程的共享状态管理——详细说明如何实现类间通信和…...

网络协议分析(CTF 入门博客)

一、什么是网络协议分析网络协议分析,就是对网络传输过程中捕获的流量数据包(通常是 .pcap 或 .pcapng 文件)进行查看、筛选、追踪和解码,从中找到关键信息。在 CTF 中,这类题目通常会给一个抓包文件,我们的…...

DM8数据库容灾避坑手册:从备份恢复到应急方案的全套操作实录(含PSEG_RECV参数详解)

DM8数据库容灾实战指南:关键文件恢复与PSEG_RECV参数深度解析 在数据库运维领域,容灾能力直接决定了业务系统的可靠性天花板。达梦DM8作为国产数据库的领军产品,其恢复机制设计既遵循经典数据库理论,又融入了独特的工程实现。本文…...

《Python程序设计与算法基础教程》P41部分练习题解答

以下解法参照书本P34中例2.25完成。P41-2.12-2题目:编写程序,输入直角三角形的两条直角边,利用勾股定理计算斜边的长度(结果保留两位小数)。编写代码:import math #导入math模块,用于开平方运算…...

基于 Spring AI Alibaba 搭建 Text-To-SQL 智能系统(简单实现)

上一篇我们完成了项目初始化、数据库搭建以及DDL生成工具类的开发,成功获取到了数据库中所有表的建表语句。本篇我们继续实现核心功能:将用户的自然语言需求转换为可执行的SQL语句并自动返回查询结果。 本文实现目标 ✅ 设计专业级Text2SQL提示词&…...

如何下载各平台上购买的网课?网课学习神器!学无止下载器让你的学习效率翻倍

🎓 网课学习神器!学无止下载器让你的学习效率翻倍 前言:你是否也遇到过这些烦恼?明明花钱买的网课,网络不好时却卡顿不断;想离线复习,却发现无法下载;珍贵课程怕到期,想永…...

EMI电路设计仿真

AriZh详细讲解了利兹线的设计参数,包括感量、电流值、开关频率等关键指标,​​强调设计状态为success的重要性,error则需回溯检查​​。他提到gap(气息)、最大工作磁密(367)等变压器相关参数&am…...

WPF Decorator:高效视觉修饰指南

理解 WPF 中的 Decorator Decorator 是 WPF 中一个抽象基类,属于 System.Windows.Controls 命名空间。它的核心作用是为子元素提供附加的视觉或布局修饰功能,例如边框、滚动条或缩放效果。Decorator 的子类通常通过单一的 Child 属性管理一个子元素&…...

Web自动化测试(01)- iFrame窗口切换

iFrame窗口切换 iframe是一种特殊的窗口,内嵌在页面之中,在前端静态HTML表示为一个标签,但是它又和新窗口一样,其中的元素无法被直接定位,需要进行切换 1. 切换至子窗口 1.1 通过ID、name切换(推荐&…...

JAVA-Mybaits

1. Mybaits简介 1.1 mybaits是什么 mybaits 是一个半 ORM (对象关系映射)框架,它内部封装了 JDBC,开发时只需要关注 SQL语句本身,不需要花费精力去处理加载驱动、创建连接、创建 statement等繁杂的过程。程序员直接编…...

二分算法 cpp

7. 二分算法 基础算法中最难的原理与模板简单难点在细节处理边界问题解集中存在二段性 模板题 : [!leetcode] 34. 在排序数组中查找元素的第一个和最后一个位置 中等 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中…...

eclipse下载、安装、编写运行helloworld教程

1.官网下载 访问官网下载最新版安装包(绿色免安装压缩包) 官网安装包下载地址:https://www.eclipse.org/downloads/packages/,选择企业级版本“Eclipse IDE for Enterprise Java and Web Developers”,操作系统版本根…...

新160个CrackMe 008,009号:Afkayas.1,Boonz-KeygenMe#1逆向分析

008Die分析文件组成Win32,无壳,语言:VB动态调试双击程序运行,弹出窗口,输入用户名和序列号(例如abcd,123456)点击ok查找字符串,双击定位字符串,向上找函数入口下断点&…...

试过30多个副业后,我只推荐这2个靠谱项目!

一晃,已经整整十年了。这十年,在互联网圈子里摸爬滚打,没有捷径,没有躺赢,若用一个词形容,便是「热辣滚烫」—— 每一步都踩得扎实,每一份收获都拼得坦荡。常有人问我:你凭什么能带出…...

基于Flask的人脸识别OOD模型API服务开发

基于Flask的人脸识别OOD模型API服务开发 1. 引言 人脸识别技术在实际应用中经常面临一个挑战:如何处理那些低质量、噪声干扰或者分布外(Out-of Distribution,OOD)的输入数据。传统的人脸识别系统往往会对这些异常样本给出高置信…...

K64F平台FXOS8700传感器驱动与姿态融合实战

1. K64_FXOS8700 驱动库深度解析:面向工业级姿态感知的双轴传感器融合实现1.1 项目定位与工程价值K64_FXOS8700 是专为 NXP K64F 微控制器(基于 ARM Cortex-M4 内核,主频 120MHz,带 FPU)设计的 FXOS8700CQ 九轴传感器驱…...

挑中年大叔头像AI头像时,看着精致不代表后面能细修

在实际设计任务中,千图网的AI生成头像功能已成为许多门店和内容团队的首选工具。日前接到需求,需要为社群活动物料快速输出一批中年大叔形象的社交头像,要求风格沉稳、辨识度高,并能方便后续调整细节。首轮构思时决定,…...

Helsinki-NLP/opus-mt-en-zh模型实战:快速搭建英译中翻译工具

1. 5分钟快速上手:用Helsinki-NLP模型实现英译中 最近在做一个需要实时翻译英文文档的项目,试了几种方案后发现Hugging Face的Helsinki-NLP/opus-mt-en-zh模型特别适合快速集成。这个由赫尔辛基大学NLP团队开发的模型,在通用领域的英译中任务…...

工业相机选型基础:曝光时间、增益与信噪比的三角平衡关系

工业相机选型基础:曝光时间、增益与信噪比的三角平衡关系导读:在视觉项目选型现场,甲方常问:“我要拍清楚高速运动的零件,还要在昏暗环境下看清细微划痕,预算能不能少点?” 作为工程师&#xff…...

稳如磐石:STM32F4 与 DP83848 打造的以太网驱动工程

stm32f4 dp83848 以太网驱动程序稳定版工程 用的armfly例程里的tcpnet 改进加了网线断线重连 端口断开重连打包发送 可跑慢百兆速度 连续实测24小时以上无错误 dp83848 phy芯片是汽车级 工业场合要比dm9161 lan8720…更稳定可靠最近在搞一个基于 STM32F4 和 DP83848 的以太网驱…...

微信小程序电商实战:前后端分离架构,20章吃透全栈开发+上线部署

在私域电商爆发、小程序成为商家标配的当下,能独立开发全栈小程序电商的开发者,早已成为职场抢手人才。可市面上多数教程要么只讲前端皮毛、要么后端逻辑模糊,要么堆砌零散知识点,学完依旧做不出可落地、可商用的项目,…...

用Anaconda玩转D2L教材:手把手教你同步李沐AI课程实验环境(Python3.8.5版)

用Anaconda玩转D2L教材:手把手教你同步李沐AI课程实验环境(Python3.8.5版) 在深度学习的学习过程中,一个与教材完全匹配的实验环境往往能事半功倍。《动手学深度学习》(D2L)作为李沐老师的经典教材&#xf…...

RecyclerView Demo - Android列表组件详解

RecyclerView Demo - Android列表组件详解 📚 目录 项目介绍 环境要求 快速开始 项目结构 代码详解 运行效果 常见问题 扩展学习 项目介绍 这是一个专门为Android初学者设计的 RecyclerView 演示项目。 RecyclerView是什么? RecyclerView是Android Jetpack组件库中的一个…...

从二维地图到UE5数字孪生:GIS的‘升维’之路与未来应用场景漫谈

从二维地图到UE5数字孪生:GIS的‘升维’之路与未来应用场景漫谈 当我们打开手机导航,二维地图已经像空气一样自然地融入日常生活。但很少有人意识到,这些看似简单的线条背后,正经历着一场从平面到立体、从静态到动态、从观察到交互…...

WinForm实战:5分钟搞定Halcon12调用笔记本摄像头扫二维码(附完整C#代码)

5分钟极简实战:Halcon12C# WinForm调用笔记本摄像头扫码全指南 每次看到商场收银台"嘀"一声完成扫码支付时,有没有想过自己动手实现类似功能?作为C#开发者,你可能已经厌倦了复杂的摄像头调用和图像处理库集成。今天我将…...

终于解决了「选文字就自动 Ctrl+C」的玄学 Bug!

终于解决了「选文字就自动 CtrlC」的玄学 Bug! 最近用飞牛 NAS 的 FntermX 终端、甚至各种 SSH 工具时,只要用鼠标拖拽选文字,就会自动触发 CtrlC 中断,满屏都是^C,复制个配置文件都要疯了! 一开始以为是终…...

Fish-Speech-1.5情感语音合成:基于RLHF的语调控制

Fish-Speech-1.5情感语音合成:基于RLHF的语调控制 1. 听见情绪的温度:当语音不再只是“读出来” 你有没有听过一段语音,明明内容普通,却让你心头一紧?或者一句简单的“谢谢”,因为语气里带着真诚的暖意&a…...

nlp_structbert_sentence-similarity_chinese-large 在嵌入式设备部署的探索与优化

nlp_structbert_sentence-similarity_chinese-large 在嵌入式设备部署的探索与优化 最近在做一个智能家居中控的项目,需要让设备能“听懂”用户指令的意图,比如“打开客厅的灯”和“把客厅的灯调亮”是不是一个意思。这自然就用到了语义相似度模型。我们…...

测试1111

测试1111...

HNU2026-计算机系统-第一次作业

2026年春第一次作业: 教材第19页,第2题; 教材第47页,第5题; 教材第48页,第6题。第 2 题 一个字节可以用两个十六进制数来表示。填写下表中缺失的项,给出不同字节模式的十进制、二进制和十六进制…...