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

Java多线程使用Wait/Notify与synchronized出现死锁无法运行问题求解

Java多线程wait/notify协作死锁问题修复方案

核心问题排查

原代码死锁及功能异常的根本原因如下:

  • 两个线程进入同步块后第一行均调用wait(),没有任何线程优先执行业务逻辑触发唤醒动作,双方永久等待直接死锁
  • 空格统计逻辑错误:原代码通过sc.next()计数得到的是单词数量,不是空格数量
  • 状态位flag逻辑完全倒置,未正确标记「空格统计完成」的状态
  • 单词修改逻辑存在边界缺陷:单字母单词会触发字符串索引越界异常

修复后完整代码

import java.io.File;
import java.io.PrintWriter;
import java.util.Scanner;

public class Dispatcher {
    public static void main(String[] args) {
        FileHandler fileHandler = new FileHandler();
        Thread countThread = new CountSpaces(new File("text.txt"), fileHandler);
        Thread changeThread = new ChangeText(new File("text.txt"), fileHandler);

        countThread.start();
        changeThread.start();
    }
}

class CountSpaces extends Thread{
    File file;
    FileHandler fileHandler;

    public CountSpaces(File file, FileHandler fileHandler) {
        this.file = file;
        this.fileHandler = fileHandler;
    }

    @Override
    public void run() {
        fileHandler.countSpace(file);
    }
}

class ChangeText extends Thread {
    File file;
    FileHandler fileHandler;

    public ChangeText(File file, FileHandler fileHandler) {
        this.file = file;
        this.fileHandler = fileHandler;
    }

    @Override
    public void run() {
        try {
            fileHandler.changeLetters(file);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class FileHandler {
    // 标记空格统计是否完成
    boolean countFinished = false;
    int spaceCount;

    void countSpace(File file) {
        try (Scanner sc = new Scanner(file)) {
            // 直接读整个文件内容统计空格,避免漏算首尾/连续空格
            StringBuilder content = new StringBuilder();
            while (sc.hasNextLine()) {
                content.append(sc.nextLine()).append("\n");
            }
            int count = 0;
            for (char c : content.toString().toCharArray()) {
                if (c == ' ') {
                    count++;
                }
            }
            synchronized (this){
                this.spaceCount = count;
                countFinished = true;
                // 统计完成唤醒修改线程
                notify();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void changeLetters(File file) throws InterruptedException {
        synchronized (this){
            // 循环等待防止虚假唤醒,直到统计完成
            while (!countFinished) {
                wait();
            }
            // 重新读文件做修改
            try (Scanner sc = new Scanner(file);
                 PrintWriter printWriter = new PrintWriter(file + "result")) {
                if (spaceCount % 2 == 0) {
                    // 偶数:首字母大写
                    while (sc.hasNext()) {
                        String word = sc.next();
                        if (word.length() == 1) {
                            printWriter.print(word.toUpperCase());
                        } else {
                            printWriter.print(word.substring(0, 1).toUpperCase() + word.substring(1));
                        }
                        // 保留原空格分隔,需完全保留原格式可直接读全字符串替换
                        printWriter.print(" ");
                    }
                } else  {
                    // 奇数:尾字母大写
                    while (sc.hasNext()) {
                        String word = sc.next();
                        if (word.length() == 1) {
                            printWriter.print(word.toUpperCase());
                        } else {
                            printWriter.print(word.substring(0, word.length() - 1)
                                    + word.substring(word.length() - 1).toUpperCase());
                        }
                        printWriter.print(" ");
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

关键调整说明

  • 调整执行顺序:统计线程优先执行空格计数,完成后再唤醒修改线程,从根源避免双向等待死锁
  • wait() 放在循环中判断状态位,符合Java多线程规范,避免虚假唤醒导致的逻辑异常
  • 修复空格统计逻辑,直接遍历全文本字符统计空格,兼容首尾空格、连续空格场景
  • 补充单字母单词的边界处理,避免索引越界

内容的提问来源于stack exchange,提问作者user17320675

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:27:03