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

