ada*_*amM 6 java io asynchronous nio
我知道Java的AsynchronousFileChannel是异步api(不会阻塞调用线程),并且可以在系统线程池中使用线程。
我的问题是:AsynchronousFileChannel操作是否具有1:1的线程比率?
换句话说,如果循环使用AsynchronousFileChannel读取100个文件,它将使用100个线程来执行该操作还是仅使用少量线程(以标准NIO方式)?
AsynchronousFileChannel一般使用的实现(例如在Linux上实际使用的实现)是SimpleAsynchronousFileChannelImpl,它基本上是提交Runnables阻塞IO读取+处理结果的线程(在同一线程中(填充Future或调用a CompletionHandler)),该线程ExecutorService作为AsynchronousFileChannel::open或作为参数提供否则,将使用默认的系统范围的默认值(这是一个无限制的缓存线程池,但是具有一些可以配置的选项)。有人认为,最好使用文件,因为它们“总是可读”的,或者至少操作系统没有提供不知道的线索。
在Windows上,使用单独的实现,称为WindowsAsynchronousFileChannelImpl。在Windows Vista / 2008和更高版本(主版本> =“ 6”)上运行时,它使用I / O完成端口(也称为IOCP),并且通常表现得更像您期望的那样:默认情况下,它使用1个线程调度读取结果(可由"sun.nio.ch.internalThreadPoolSize"系统配置)属性)和用于处理的缓存线程池。
因此,回答您的问题:如果您不向提供自己的ExecutorService(例如固定的)AsynchronousFileChannel::open,那么它将是1:1的关系,因此100个文件的线程数为100;除了一个不古老的Windows,默认情况下将有1个线程处理I / O,但如果所有结果同时(不太可能但仍然)到达并且您使用CompletionHandlers,则它们也会在各自的线程中被调用。
编辑:我实现了100个文件的读取,并在Linux和Windows(openjdk8)上运行它,并且它1)确认两个类均实际使用了哪些类(为此删除,TF.class同时仍在命令行中指定它并查看stacktrace),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());
}
}
Run Code Online (Sandbox Code Playgroud)
和
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;
}
}
Run Code Online (Sandbox Code Playgroud)
编译这些文件,并将它们放在包含100个名为的文件的文件夹some0.txt中some99.txt,每个文件的大小为1Mb,以免读取速度太快,请按
java -Djava.nio.channels.DefaultThreadPool.threadFactory=TF AsynchFileChannelDemo
Run Code Online (Sandbox Code Playgroud)
打印的数字是线程工厂创建新线程的次数。