我理解Java的AsynchronousFileChannel是一个异步api (不阻塞调用线程),可以在系统线程池中使用线程。
我的问题是: AsynchronousFileChannel操作是否有1:1的线程比率?
换句话说,如果一个循环使用AsynchronousFileChannel读取100个文件,那么它是使用100个线程来读取,还是只使用少量的线程(以标准的NIO方式)?
发布于 2016-09-16 06:11:37
一般使用的AsynchronousFileChannel实现(在Linux上实际使用)是SimpleAsynchronousFileChannelImpl,它基本上将阻塞IO读取+进程的Runnables提交给ExecutorService,该线程要么填充未来,要么调用CompletionHandler,后者要么作为AsynchronousFileChannel::open的参数提供,要么使用默认的系统范围的线程池( 是是一个无界缓存线程池,但有一些可以配置选项)。一些想认为这是最好的文件,因为它们“总是可读的”,或者至少操作系统没有提供任何线索表明它们不是。
在Windows上使用了一个单独的实现,称为WindowsAsynchronousFileChannelImpl。它使用6,通常的行为更像您所期望的那样:默认情况下,它使用一个线程来分派读取结果(可由"sun.nio.ch.internalThreadPoolSize"系统属性配置)和一个缓存的线程池进行处理。
因此,回答了您的问题:如果您不向AsynchronousFileChannel::open提供您自己的ExecutorService (比如固定的),那么它将是1:1的关系,因此100个文件将有100个线程;除了一个非古老的ExecutorService,默认情况下将有一个线程处理I/O,但是如果所有结果同时到达(不太可能,但仍然是这样),并且使用CompletionHandlers,它们也将在自己的线程中被调用。
编辑::我实现了读取100个文件,并在Linux和 (openjdk8)上运行了它,它1)确认了在这两种情况下实际使用了哪些类(对于删除TF.class,同时仍然在命令行中指定它并查看堆栈跟踪),2)某种程度上确认了所使用线程的数量: Linux上有100个线程,如果完成处理速度快,则在上有4个线程(如果不使用CompletionHandlers,则相同);如果完成处理速度慢,则在CompletionHandlers上使用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.txt的文件到some99.txt,每个文件的大小为1Mb,这样读取就不会太快,运行它如下
java -Djava.nio.channels.DefaultThreadPool.threadFactory=TF AsynchFileChannelDemo打印的数字是线程工厂创建新线程的次数。
https://stackoverflow.com/questions/39501924
复制相似问题