
本文旨在探讨Java中如何在不同运行类之间安全有效地共享和更新变量值,特别是在需要实时监控操作进度的场景。我们将通过三种核心策略——观察者模式(推模型)、轮询模式(拉模型)以及基于多线程的共享状态管理——来详细阐述如何实现类间的通信与数据同步,并提供相应的代码示例和最佳实践建议。
在Java应用程序开发中,不同类之间的数据交互是常见的需求。尤其是在执行耗时操作(如文件拷贝、网络下载)时,我们通常需要在一个类中执行任务,而在另一个类中实时显示或监控任务的进度。直接通过静态变量进行访问虽然可行,但在多线程或复杂场景下可能导致难以维护和调试的问题。本教程将深入探讨几种更健壮、更专业的解决方案。
设想一个场景:CopyFile 类负责大文件的分块拷贝,它会不断更新已拷贝的数据量。而 ProgressMonitor 类则需要在用户界面或控制台实时显示这个进度。核心挑战在于:
下面我们将介绍三种主流的实现策略。
立即学习“Java免费学习笔记(深入)”;
观察者模式是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。在这种模式下,执行任务的类(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("文件拷贝完成!");
}
}优点:
轮询模式与观察者模式相反,它不依赖于主动通知。在这种模式下,负责监控进度的类(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;
}
}优点:
缺点:
当 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 (!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() + ": 进度监控结束,任务已完成。");
}
}注意事项:
选择哪种策略取决于具体的应用场景和需求:
通用建议:
通过以上三种策略,开发者可以根据项目的具体需求,灵活选择最适合的方式来实现在Java中不同运行类之间安全、高效地共享变量和更新进度。
以上就是Java类间变量共享与进度更新的实现策略的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号