首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java AsynchronousFileChannel -线程使用

Java AsynchronousFileChannel -线程使用
EN

Stack Overflow用户
提问于 2016-09-15 01:28:38
回答 1查看 1.6K关注 0票数 9

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

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

换句话说,如果一个循环使用AsynchronousFileChannel读取100个文件,那么它是使用100个线程来读取,还是只使用少量的线程(以标准的NIO方式)?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 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个线程。虽然它很难看,但代码是:

代码语言:javascript
复制
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());
    }
}

代码语言:javascript
复制
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,这样读取就不会太快,运行它如下

代码语言:javascript
复制
java -Djava.nio.channels.DefaultThreadPool.threadFactory=TF AsynchFileChannelDemo

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

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39501924

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档