Java AsynchronousFileChannel - 线程使用情况

时间:2016-09-15 01:28:38

标签: java asynchronous io nio

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

我的问题是:AsynchronousFileChannel操作的线程比是1:1吗?

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

1 个答案:

答案 0 :(得分:4)

一般使用的

AsynchronousFileChannel实现(实际上在Linux上使用)是SimpleAsynchronousFileChannelImpl,它基本上提交Runnables,阻止IO读取+处理结果在同一个线程中(填写一个将来或CompletionHandler}调用ExecutorService,其中"sun.nio.ch.internalThreadPoolSize"作为参数提供给AsynchronousFileChannel::open,否则使用默认的系统范围(is无界限can be configured缓存线程池,但有一些选项think)。有些WindowsAsynchronousFileChannelImpl表示文件是最好的,因为它们总是可读的#34;或者至少操作系统没有提供任何他们不知道的线索。

在Windows上,使用了一个名为I/O completion ports的单独实现。它在Windows Vista / 2008及更高版本(主要版本> =" 6")上运行时使用enter image description here aka IOCP,并且通常表现得更像您期望的:默认情况下它使用1个线程进行调度读取结果(可由ExecutorService系统属性配置)和用于处理的缓存线程池。

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

编辑:我实现了100个文件的读取并在Linux和Windows上运行(openjdk8)并且1)确认两个实际使用的类(用于删除CompletionHandlers仍然在命令行中指定它并查看堆栈跟踪),2)确认使用的线程数:在Linux上为100,在Windows上为4,如果完成处理速度很快(如果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()); } } 不是,那么它将是相同的如果完成处理很慢,则在Windows上使用100)。虽然很丑,但代码是:

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;
    }
}

some0.txt

编译这些内容,将它们放在一个包含100个名为some99.txtjava -Djava.nio.channels.DefaultThreadPool.threadFactory=TF AsynchFileChannelDemo 的文件的文件夹中,每个文件大小为1Mb,这样读取速度就不会太快,请将其作为

运行
button:focus{
outline:0px;
}

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