AsynchronousFileChannel
一般使用的实现(以及实际使用的,例如在Linux上)是简单的异步 FileChannelImpl基本上提交Runnables
在同一个线程中执行阻塞 IO 读取+处理的结果(要么填充 future 要么调用CompletionHandler
) to an ExecutorService
其中任一作为参数提供AsynchronousFileChannel::open,否则使用默认的系统范围的(is无界缓存线程池,但有一些选项可以配置). Some think这是对文件可以完成的最好的操作,因为它们“始终可读”,或者至少操作系统没有提供任何它们不可读的线索。
在 Windows 上,使用一个单独的实现,称为Windows 异步 FileChannelImpl。它用I/O 完成端口又名 IOCP,在 Windows Vista/2008 及更高版本(主要版本 >=“6”)上运行时,通常表现得更像您所期望的:默认情况下,它使用 1 个线程来分派读取结果(可通过以下方式配置)"sun.nio.ch.internalThreadPoolSize"
系统属性)和用于处理的缓存线程池。
So, 回答你的问题: 如果你不提供自己的ExecutorService
(说一个固定的)AsynchronousFileChannel::open
,那么就会是1:1的关系,所以100个文件就有100个线程;除了非古老的 Windows,默认情况下会有 1 个线程处理 I/O,但如果所有结果同时到达(不太可能但仍然如此)并且您使用CompletionHandlers
,它们也将在自己的线程中被调用。
Edit:我实现了对 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());
}
}
and
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.txt
to some99.txt
,每个大小为 1Mb,因此读取速度不会太快,运行如下
java -Djava.nio.channels.DefaultThreadPool.threadFactory=TF AsynchFileChannelDemo
打印的数字是线程工厂创建新线程的次数。