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

Java多线程读写文件异常:写入全为0问题排查求助

生产者-消费者线程模型导致目标文件全是0的问题分析与修复

你遇到的问题是典型的生产者-消费者模型中同步机制失效、线程协调不当加上代码逻辑错误导致的,我来帮你拆解问题并给出修复方案:

先看你的代码核心问题点:

1. 同步锁完全没用

你给run方法加了synchronized,但这个锁的是当前线程对象(oku或yaz实例),两个线程的锁根本不是同一个,完全起不到同步共享data对象的作用。原本你注释掉的synchronized(d)块才是正确的方向,但现在没启用,导致生产者修改d.value时,消费者看不到最新值,甚至一直读取初始的0。

2. 生产者的资源关闭逻辑严重错误

在oku的run方法里,sc.close()被放在了while循环内部——这意味着第一次读取整数后就直接关闭了Scanner,后面的循环根本读不到任何数据,生产者等于只执行了一次(甚至可能没执行成功),消费者却一直在循环5000次读取初始的0。

3. 线程间没有协调机制

生产者和消费者完全是各跑各的:消费者可能在生产者还没开始读取数据时,就已经把d.value的初始值0写了5000次;就算生产者能正常读取,也会出现生产者覆盖未被消费的数据,或者消费者重复读取旧数据的情况。

4. 异常处理太粗糙

两个线程都用catch(Exception ex){}吞掉了所有异常,比如文件找不到、权限不足、数据格式错误等问题都不会被你发现,很可能生产者根本没读到数据,消费者自然只能写0。


修复后的代码示例

首先修改data类,添加线程协调的状态标记:

public class data {
    int value;
    // 标记是否有未被消费的新数据
    boolean isAvailable = false;
    // 标记生产者是否已经完成所有数据的读取
    boolean isFinished = false;
}

然后是生产者类oku,修复同步逻辑和资源管理:

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

public class oku implements Runnable {
    private final data d;
    private static final int TOTAL_COUNT = 5000;

    public oku(data d) {
        this.d = d;
    }

    @Override
    public void run() {
        File inputFile = new File("/home/ayyuce/Desktop/ali.dat");
        // 使用try-with-resources自动关闭Scanner,避免资源泄漏
        try (Scanner sc = new Scanner(inputFile)) {
            for (int i = 0; i < TOTAL_COUNT; i++) {
                synchronized (d) {
                    // 等待消费者取走前一次生产的数据
                    while (d.isAvailable) {
                        d.wait();
                    }
                    // 如果文件还有数据就读取,否则填充0(根据需求调整)
                    d.value = sc.hasNextInt() ? sc.nextInt() : 0;
                    d.isAvailable = true;
                    // 通知消费者可以读取新数据了
                    d.notify();
                }
            }
            // 所有数据生产完成,标记状态并通知消费者
            synchronized (d) {
                d.isFinished = true;
                d.notify();
            }
        } catch (Exception ex) {
            // 打印异常信息,方便排查问题
            ex.printStackTrace();
        }
    }
}

接下来是消费者类yaz,同步逻辑和资源管理修复:

import java.io.File;
import java.io.PrintWriter;

public class yaz implements Runnable {
    private final data d;
    private static final int TOTAL_COUNT = 5000;

    public yaz(data d) {
        this.d = d;
    }

    @Override
    public void run() {
        File outputFile = new File("/home/ayyuce/Desktop/veri.dat");
        // try-with-resources自动关闭PrintWriter
        try (PrintWriter writer = new PrintWriter(outputFile)) {
            for (int i = 0; i < TOTAL_COUNT; i++) {
                synchronized (d) {
                    // 等待生产者生产新数据,或者生产者结束
                    while (!d.isAvailable && !d.isFinished) {
                        d.wait();
                    }
                    // 如果生产者结束且没有未消费数据,提前退出
                    if (d.isFinished && !d.isAvailable) {
                        break;
                    }
                    // 写入数据
                    writer.println(d.value);
                    d.isAvailable = false;
                    // 通知生产者可以生产下一个数据了
                    d.notify();
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

main_class保持不变即可:

public class main_class {
    public static void main(String[] args) {
        data d = new data();
        oku producer = new oku(d);
        yaz consumer = new yaz(d);
        Thread t1 = new Thread(producer);
        Thread t2 = new Thread(consumer);
        t1.start();
        t2.start();
    }
}

关键修复总结

  • 用共享的data对象作为锁:确保生产者和消费者的同步块使用同一个锁,避免数据竞争。
  • 添加线程协调机制:通过isAvailable和isFinished标记,配合wait()/notify()实现生产者和消费者的节奏匹配,避免空读、重复读。
  • 正确管理资源:使用try-with-resources自动关闭IO资源,避免过早关闭或资源泄漏。
  • 完善异常处理:打印异常信息,快速排查IO或线程相关的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:51:39