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

Java多线程同步求助:如何阻止线程在Excel操作完成前启动?

问题分析

你当前的代码存在两个核心问题:

  1. 线程任务与实际操作脱节:MyRunnable的run方法只是简单sleep,和创建Excel、打开Excel、获取文件大小的实际操作完全无关。比如t2线程启动后,4秒就结束了,但此时Excel还处于打开状态,主线程的t2.join()自然无法等待Excel关闭。
  2. 关键操作未绑定到对应线程:打开Excel的excelFileHandler.openSpreadSheet调用是在主线程中执行的,而非t2线程,导致t2线程根本不负责等待Excel关闭的逻辑。
解决方案

要实现“等待Excel关闭后再启动获取文件大小的线程”,需要做到两点:

  • 让负责打开Excel的线程(t2)真正等待Excel进程终止。
  • 主线程必须在t2完全结束(即Excel关闭)后,再启动t3线程。

具体步骤:

  1. 修改ExcelFileHandler.openSpreadSheet方法,使其返回启动的Excel进程对象,这样可以在代码中等待进程结束。
  2. 为每个任务编写独立的Runnable实现,避免通用MyRunnable的无效逻辑。
  3. 主线程中严格按顺序:启动t1→等待t1完成→启动t2→等待t2完成(Excel关闭)→启动t3→等待t3完成。
修改后的代码示例

首先调整ExcelFileHandler的openSpreadSheet方法(假设原来的实现是通过Runtime.getRuntime().exec打开Excel):

import java.io.File;
import java.io.IOException;

public class ExcelFileHandler {
    public void createExcelFile(String fileName) throws IOException {
        // 原有的POI创建Excel逻辑,此处省略
        File file = new File(fileName);
        if (!file.exists()) {
            file.createNewFile();
            // 这里添加POI写入空Excel的代码
        }
    }

    public Process openSpreadSheet(String fileName) throws IOException {
        // 启动Excel进程并返回该进程,/wait参数让命令行等待Excel关闭
        String command = "cmd /c start /wait excel.exe \"" + new File(fileName).getAbsolutePath() + "\"";
        return Runtime.getRuntime().exec(command);
    }

    public long getFileSize(String fileName) {
        File file = new File(fileName);
        return file.exists() ? file.length() : -1;
    }
}

然后编写独立的任务Runnable:

// 创建Excel文件的任务
class CreateFileRunnable implements Runnable {
    private final ExcelFileHandler handler;
    private final String fileName;

    public CreateFileRunnable(ExcelFileHandler handler, String fileName) {
        this.handler = handler;
        this.fileName = fileName;
    }

    @Override
    public void run() {
        System.out.println("线程t1启动:创建Excel文件");
        try {
            handler.createExcelFile(fileName);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("线程t1结束:Excel文件创建完成");
    }
}

// 打开Excel并等待关闭的任务
class OpenExcelRunnable implements Runnable {
    private final ExcelFileHandler handler;
    private final String fileName;

    public OpenExcelRunnable(ExcelFileHandler handler, String fileName) {
        this.handler = handler;
        this.fileName = fileName;
    }

    @Override
    public void run() {
        System.out.println("线程t2启动:打开Excel文件");
        try {
            Process excelProcess = handler.openSpreadSheet(fileName);
            // 等待Excel进程终止(即用户关闭Excel)
            excelProcess.waitFor();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("线程t2结束:Excel已关闭");
    }
}

// 获取文件大小的任务
class GetFileSizeRunnable implements Runnable {
    private final ExcelFileHandler handler;
    private final String fileName;

    public GetFileSizeRunnable(ExcelFileHandler handler, String fileName) {
        this.handler = handler;
        this.fileName = fileName;
    }

    @Override
    public void run() {
        System.out.println("线程t3启动:获取Excel文件大小");
        long size = handler.getFileSize(fileName);
        System.out.println("Excel文件大小:" + size + " 字节");
        System.out.println("线程t3结束");
    }
}

最后修改主线程逻辑:

public class ExcelFileCreator {
    private static final ExcelFileHandler excelFileHandler = new ExcelFileHandler();
    private static final String FILE_NAME = "coggis.xlsx";

    public static void main(String[] args) {
        Thread t1 = new Thread(new CreateFileRunnable(excelFileHandler, FILE_NAME), "t1");
        Thread t2 = new Thread(new OpenExcelRunnable(excelFileHandler, FILE_NAME), "t2");
        Thread t3 = new Thread(new GetFileSizeRunnable(excelFileHandler, FILE_NAME), "t3");

        try {
            // 启动t1,等待创建完成
            t1.start();
            t1.join();

            // 启动t2,等待Excel关闭
            t2.start();
            t2.join();

            // 启动t3,获取文件大小
            t3.start();
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("所有任务完成");
    }
}
关键说明
  1. openSpreadSheet的start /wait参数:在Windows命令中,start /wait会让命令行等待启动的Excel进程结束后再继续,这样Process.waitFor()就能正确捕获Excel关闭的事件。
  2. 线程顺序执行:通过join()方法严格保证t1完成后才启动t2,t2完成(Excel关闭)后才启动t3,彻底解决了t3提前启动的问题。
  3. 任务解耦:每个Runnable只负责单一任务,代码逻辑更清晰,也便于维护和调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 05:35:23