You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 14:31:14