AsynchronousFileChannel
реализация используется в целом (и фактически используемых, например, в Linux) является SimpleAsynchronousFileChannelImpl, который в основном представляет Runnables
, которые блокирование ввода-вывода для чтения + результат процесса в том же потоке (либо заполнить будущее или вызвать CompletionHandler
) к ExecutorService
, которые либо поставляется в качестве аргумента AsynchronousFileChannel::open
, или же используется системная система по умолчанию (которая содержит is неограниченный пул кешированных потоков, но имеет некоторые параметры, которые can be configured). Некоторые think, что это лучшее, что можно сделать с файлами, так как они «всегда читаемы» или, по крайней мере, ОС не дает никакой подсказки, которой они не являются.
В Windows используется отдельная реализация, которая называется WindowsAsynchronousFileChannelImpl. Он использует I/O completion ports aka IOCP при работе в Windows Vista/2008 и более поздних версиях (основная версия> = «6») и, как правило, ведет себя так же, как и следовало ожидать: по умолчанию он использует 1 поток для отправки результатов чтения (настраивается по системному свойству "sun.nio.ch.internalThreadPoolSize"
) и пул кэшированных потоков для обработки.
Так, отвечая на ваш вопрос: если вы не предоставите свой собственный ExecutorService
(скажем, фиксированный один), чтобы AsynchronousFileChannel::open
, то это будет 1: 1 отношения, так что будет 100 нитей для 100 файлов; за исключением не древней Windows, где по умолчанию будет задействован один поток обработки ввода-вывода, но если все результаты придут одновременно (маловероятно, но все же), и вы используете CompletionHandlers
, они также будут вызываться каждый в своем потоке.
Edit: Я осуществил чтение 100 файлов и запустил его на Linux и Windows (openjdk8) и 1) подтверждает, какие классы фактически используются на обоих (для этого удалить TF.class
при этом указав его в командной строке и см. stacktrace), 2) тип подтверждения количества используемых потоков: 100 в Linux, 4 в Windows, если обработка завершения выполняется быстро (это будет то же самое, если CompletionHandlers
не используется), 100 в Windows, если обработка завершения выполняется медленно. Уродливый, как это, код:
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
, каждый из которых 1Мб по размеру, так что чтение ISN» t слишком быстро, запустите его как
java -Djava.nio.channels.DefaultThreadPool.threadFactory=TF AsynchFileChannelDemo
Число напечатанных - количество раз, когда новая нить была создана фабрикой нитей.
Не совсем. [Когда AsynchronousFileChannel создается без указания пула потоков, тогда канал ассоциируется с зависящим от системы пулом потоков по умолчанию, который может использоваться совместно с другими каналами. Пул потоков по умолчанию настроен на свойства системы, определенные классом AsynchronousChannelGroup.] (Https://docs.oracle.com/javase/8/docs/api/java/nio/channels/FileChannel.html) – EJP
@EJP, спасибо за отзыв. Я, безусловно, отредактирую свой ответ или удалю его, если он не выздоравливает, но сначала я хотел бы понять это лучше. Насколько я понимаю, этот пул потоков создан [здесь] (http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/nio/ch/ThreadPool. java # l95), и поэтому он использует настройки «threadFactory» и «initialSize», но он по-прежнему является неограниченным кэшированным пулом потоков. Должен ли я сделать более понятным, что он не создан по каждому каналу в моем ответе? Или что-то не так с моим ответом? – starikoff
По умолчанию общий пул потоков по умолчанию, казалось, указывал в направлении отношения не 1: 1: многие файлы могут считываться одновременно с использованием фиксированного меньшего количества потоков с использованием магии NIO. Если он этого не сделает, то я не знаю, какой будет польза от этого над стандартным java.ion и завершение выполнения в потоке и возвращение будущего. – adamM