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
相关产品推荐
相关产品推荐

