Java GUI版WordCount项目thread synchronization实现方案
实现方案
你的代码原本把所有计数逻辑都写在Swing的事件回调里,既没有拆分工作线程,也没有处理并发访问的互斥问题,以下实现方案完全覆盖线程同步的核心知识点,同时符合Swing的线程模型要求,不会出现偶发崩溃、结果错乱的问题。
核心同步逻辑覆盖三个并发场景:
- 计数任务读取文本内容、清空按钮修改文本内容的互斥访问,避免脏读
- 工作线程和UI线程的状态可见性保证,避免重复启动计数任务
- 跨线程更新UI的线程协调,避免Swing组件跨线程访问的异常
第一步:新增依赖导入
在类的导入部分新增两个并发相关的类:
import java.util.concurrent.locks.ReentrantLock; import javax.swing.SwingWorker;
第二步:添加线程同步相关的成员变量
在类的成员变量区域加入锁和状态标记:
// 全局互斥锁:所有涉及共享资源(文本内容、计数状态)的操作都要持有该锁 private final ReentrantLock countLock = new ReentrantLock(); // 计数任务运行状态标记,volatile保证多线程环境下的内存可见性 private volatile boolean isCounting = false;
第三步:修改Count按钮的点击事件逻辑
把原来直接在UI线程跑的计数逻辑拆到工作线程执行,加锁保证并发安全:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) { countLock.lock(); try { // 已有计数任务运行时直接返回,避免重复提交 if (isCounting) { return; } isCounting = true; // 锁内读取文本快照,避免读取过程中文本被清空导致数据不一致 final String content = txt.getText(); // 置灰按钮从交互层避免重复点击 jButton1.setEnabled(false); // SwingWorker是Swing官方提供的线程同步工具,自动协调工作线程和UI线程 SwingWorker<int[], Void> countTask = new SwingWorker<>() { @Override protected int[] doInBackground() { // 耗时计数逻辑完全在工作线程执行,不阻塞UI int charCount = 0; int wordCount = 0; char[] textArr = content.toCharArray(); for (int i = 0; i < textArr.length; i++) { // 统计字符数 if (i > 0 || (textArr[0] != ' ' && i == 0)) { charCount++; } // 统计单词数 if (((i > 0) && (textArr[i] != ' ') && (textArr[i-1] == ' ')) || ((textArr[0] != ' ') && (i == 0))) { wordCount++; } } return new int[]{charCount, wordCount}; } @Override protected void done() { // done方法由SwingWorker自动调度到UI线程执行,不需要手动切线程,属于内置的线程同步保证 try { int[] res = get(); letter.setText(nf.format(res[0])); word.setText(nf.format(res[1])); } catch (Exception ex) { ex.printStackTrace(); } finally { // 重置状态时也要拿锁,和其他操作互斥 countLock.lock(); try { isCounting = false; jButton1.setEnabled(true); } finally { countLock.unlock(); } } } }; countTask.execute(); } finally { countLock.unlock(); } }
第四步:修改Clear按钮的点击事件逻辑
清空操作也要持有同一把锁,和计数操作互斥:
private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) { countLock.lock(); try { txt.setText(null); letter.setText(null); word.setText(null); } finally { countLock.unlock(); } }
涉及的线程同步知识点说明
ReentrantLock互斥锁:保证同一时间只有一个线程能操作共享的文本内容和计数状态,彻底避免计数过程中文本被修改导致的结果错误volatile关键字:禁止指令重排、保证多线程环境下isCounting状态的可见性,不会出现UI线程已经把状态设为true,工作线程还读到false的问题SwingWorker线程协作:封装了工作线程和UI线程的通信逻辑,保证耗时逻辑在后台跑、UI更新在事件派发线程执行,完全符合Swing的线程安全规则
直接替换对应方法的代码即可测试,大文本下不会卡UI,快速交替点Count和Clear也不会出现结果错乱。
内容的提问来源于stack exchange,提问作者Ibad hussain
相关产品推荐
相关产品推荐

