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

Java中仅用synchronized、wait、notify、sleep控制文件读取线程数量

实现有限并发的文件循环读取线程

嘿,我看你需要实现一个限制并发数的文件循环读取线程——每个线程完整读取文件、短暂休眠后再重复读取,同时最多允许指定数量n的线程同时读取。这个需求用Java并发包中的Semaphore就能完美解决,它专门用来控制同时访问某个资源的线程数量。

核心思路

用Semaphore作为并发控制器:

  • 初始化时指定许可数n,代表最多允许n个线程同时进入文件读取环节
  • 线程每次读取文件前调用acquire()获取许可(如果已满则阻塞等待)
  • 读取完成后必须调用release()归还许可,确保其他线程能获取
  • 用finally块包裹release(),避免读取文件抛出异常时许可无法归还导致死锁

完整实现代码

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.concurrent.Semaphore;

// 文件读取线程类
class Reader implements Runnable {
    private final Semaphore semaphore;
    private final String filePath;
    private final String threadName;
    private volatile boolean running = true; // 用于优雅停止线程

    public Reader(Semaphore semaphore, String filePath, String threadName) {
        this.semaphore = semaphore;
        this.filePath = filePath;
        this.threadName = threadName;
        // 启动线程
        new Thread(this, threadName).start();
    }

    @Override
    public void run() {
        while (running) {
            try {
                // 1. 获取许可,最多n个线程能同时走到这一步
                semaphore.acquire();
                System.out.printf("[%s] 开始读取文件%n", threadName);

                // 2. 完整读取文件内容(这里示例读取为字节数组,也可以读成字符串)
                byte[] fileContent = Files.readAllBytes(Paths.get(filePath));
                // 可以在这里处理文件内容,比如传递给其他任务
                System.out.printf("[%s] 文件读取完成,内容长度:%d字节%n", threadName, fileContent.length);

            } catch (InterruptedException e) {
                // 线程被中断时终止循环
                Thread.currentThread().interrupt();
                running = false;
                System.err.printf("[%s] 线程被中断%n", threadName);
            } catch (IOException e) {
                System.err.printf("[%s] 文件读取失败:%s%n", threadName, e.getMessage());
            } finally {
                // 3. 无论读取成功还是失败,都归还许可
                semaphore.release();
                System.out.printf("[%s] 已释放读取许可%n", threadName);
            }

            // 4. 短暂休眠后再次尝试读取
            try {
                Thread.sleep(1000); // 休眠1秒,可根据需求调整
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                running = false;
            }
        }
        System.out.printf("[%s] 线程停止%n", threadName);
    }

    // 优雅停止线程的方法
    public void stopReading() {
        this.running = false;
    }
}

// 测试主类
public class FileReaderApp {
    public static void main(String[] args) {
        int maxConcurrentThreads = 3; // 指定最多3个线程同时读取
        String targetFile = "test.txt"; // 替换为你的文件路径

        // 初始化Semaphore,指定最大并发数
        Semaphore semaphore = new Semaphore(maxConcurrentThreads);

        // 创建5个读取线程(超过最大并发数,测试控制效果)
        for (int i = 1; i <= 5; i++) {
            new Reader(semaphore, targetFile, "Reader-" + i);
        }
    }
}

关键细节说明

  • Semaphore的公平性:如果需要线程按启动顺序获取许可,可以用new Semaphore(maxConcurrentThreads, true)初始化,默认非公平模式吞吐量更高
  • 文件读取的灵活性:示例用Files.readAllBytes读取完整文件,你也可以换成Files.readAllLines读取为字符串列表,或者用传统的IO流实现
  • 线程优雅停止:通过volatile boolean running变量控制循环,避免强制中断导致的资源泄漏
  • 异常处理:捕获文件IO异常和线程中断异常,确保线程不会因为单次读取失败而崩溃

内容的提问来源于stack exchange,提问作者José Manuel Madrigal Ramírez

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:40:26