gpt4 book ai didi

Java AsynchronousFileChannel - 线程使用

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:16:24 24 4
gpt4 key购买 nike

我理解 Java 的 AsynchronousFileChannel 是一个异步 api(不阻塞调用线程)并且可以使用系统线程池中的线程。

我的问题是:AsynchronousFileChannel 操作是否具有 1:1 的线程比率?

换句话说,如果一个循环使用 AsynchronousFileChannel 读取 100 个文件,它会使用 100 个线程来执行此操作还是仅使用少量线程(以标准 NIO 方式)?

最佳答案

一般使用的

AsynchronousFileChannel 实现(例如在 Linux 上实际使用)是 SimpleAsynchronousFileChannelImpl它基本上提交 Runnables 阻塞 IO 读取 + 处理结果在同一线程(填充 future 或调用 CompletionHandler)到 ExecutorService哪个作为参数提供给 AsynchronousFileChannel::open ,或者使用默认的系统范围的线程池(is 一个无界缓存线程池,但有一些选项 can be configured )。一些think这是对文件的最佳处理方式,因为它们“始终可读”,或者至少操作系统没有提供任何它们不可读的线索。

在 Windows 上使用一个单独的实现,称为 WindowsAsynchronousFileChannelImpl .它使用 I/O completion ports a.k.a IOCP 在 Windows Vista/2008 及更高版本(主要版本 >=“6”)上运行时通常表现得更像您期望的那样:默认情况下它使用 1 个线程来分派(dispatch)读取结果(可通过 "sun.nio.configuration 进行配置。 ch.internalThreadPoolSize" 系统属性)和用于处理的缓存线程池。

因此,回答您的问题:如果您不向AsynchronousFileChannel::open 提供自己的ExecutorService(比如一个固定的服务) ,那么就会是1:1的关系,所以100个文件会有100个线程;除了非古老的 ​​Windows,默认情况下将有 1 个线程处理 I/O,但如果所有结果同时到达(不太可能但仍然如此)并且您使用 CompletionHandlers,它们将在其也有自己的线程。

编辑: 我实现了对 100 个文件的读取并在 Linux 和 Windows (openjdk8) 上运行它,它 1) 确认在这两个文件上实际使用了哪些类(为此删除 TF.class 同时仍然在命令行中指定它并查看堆栈跟踪),2) 确认使用的线程数:Linux 上为 100,如果完成处理速度很快,Windows 上为 4(如果 CompletionHandlers 未使用),如果完成处理缓慢,则在 Windows 上为 100。虽然丑陋,但代码是:

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.file.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
import java.util.*;

public class AsynchFileChannelDemo {

public static final AtomicInteger ai = new AtomicInteger();

public static void main(String[] args) throws IOException, InterruptedException, ExecutionException {
final List<ByteBuffer> bufs = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 100; i++) {
Path p = Paths.get("some" + i + ".txt");
final ByteBuffer buf = ByteBuffer.allocate(1000000);
AsynchronousFileChannel ch = AsynchronousFileChannel.open(p, StandardOpenOption.READ);
ch.read(buf, 0, buf, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer result, ByteBuffer attachment) {
bufs.add(buf);
// put Thread.sleep(10000) here to make it "long"
}

@Override
public void failed(Throwable exc, ByteBuffer attachment) {
}
});
}
if (args.length > 100) System.out.println(bufs); // never
System.out.println(ai.get());
}
}

import java.util.concurrent.ThreadFactory;

public class TF implements ThreadFactory {
@Override
public Thread newThread(Runnable r) {
AsynchFileChannelDemo.ai.incrementAndGet();
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
}

编译这些,把它们放在一个有 100 个文件的文件夹中,文件名为 some0.txtsome99.txt,每个文件大小为 1Mb,这样读取速度不会太快, 运行它

java -Djava.nio.channels.DefaultThreadPool.threadFactory=TF AsynchFileChannelDemo

打印的数字是线程工厂创建新线程的次数。

关于Java AsynchronousFileChannel - 线程使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39501924/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com