my contact information
Mailmesophia@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Describe the basic knowledge of NIO at the ava level, used for basic review
In Java, NIO (Non-blocking I/O or New I/O) is a new set of input/output operation APIs introduced in Java SE 1.4 and subsequent versions.
Compared with the traditional IO model, it provides higher efficiency and better concurrent processing capabilities. The key feature of NIO is its non-blocking feature, which enables a single thread to manage multiple I/O channels, greatly improving application performance in high-concurrency scenarios.
Java NIO is particularly suitable for situations where a large number of concurrent connections need to be processed. For example, in a network server, one thread can manage thousands of client connections without allocating a separate thread for each connection. This can significantly reduce system resource consumption and improve processing power.
Channels are the medium of data flow in Java NIO. They are bidirectional and can be used to read data as well as write data. The main advantage of channels is that they are non-blocking, which means that a thread can manage multiple channels. When no events occur on a channel, the thread will not be blocked but can handle other tasks. The main channel types include:
FileChannel
: Used for file reading and writing operations. It can be used to write data from the buffer to the file, or read data from the file into the buffer.SocketChannel
: TCP connection used in network communication, which can be used to read and write data.ServerSocketChannel
: Used to accept new SocketChannel connections, similar to traditional ServerSocket.DatagramChannel
: Used for UDP communication, can send and receive datagrams. A buffer is an object used to store data in NIO. It is a byte array to which data can be written and read. A buffer has a specific capacity and two important properties: position and limit.
The main types of buffers areByteBuffer
、CharBuffer
、ShortBuffer
、IntBuffer
、LongBuffer
、FloatBuffer
andDoubleBuffer
, each type corresponds to a primitive data type.
A selector is a multiplexer in NIO that allows a single thread to monitor multiple channels for events such as read, write, connect, and receive events. When one of the channels is ready for I/O operations, the selector notifies the application. The use of selectors greatly improves the concurrent processing capabilities of network applications because there is no need to create a thread for each connection.
The main methods of the selector are:
select()
: Block until at least one channel is ready for I/O operation.selectedKeys()
: Returns a Set containing the SelectionKey objects of all prepared channels.wakeup()
: Interrupt blockingselect()
transfer.SelectionKey
It is the association between a selector and a channel. It represents the registration status of a channel on a selector, including the channel, selector, event set of interest, and ready event set.
This is the most traditional I/O model. In Java, the traditional Socket and ServerSocket APIs are based on blocking I/O. In this mode, when a thread initiates a read or write operation, the thread will be blocked until the I/O operation is completed. If there is no data to read in the read operation, or the write operation cannot be completed immediately, the thread will wait until the operation is completed.
Features:
Non-blocking I/O is part of the Java NIO (New I/O) framework, which allows threads to initiate read and write operations without being blocked. If a read operation has no data to read, or a write operation cannot be completed immediately, the thread will not be suspended, but can continue to perform other tasks.
Features:
Multiplexing is to monitor multiple file descriptors at the same time through a thread, and operate on a descriptor only when it is ready (usually means that the data is readable or the write buffer is writable). Selector is used in Java to implement multiplexing.
Features:
Notice:
In practical applications, non-blocking I/O is often used in combination with multiplexing. For example, a server can use a Selector to monitor multiple SocketChannels. When a SocketChannel has data to read or write, the Selector will notify the server, and the server will then use a non-blocking method to process this specific SocketChannel.
In Java, Stream and Channel are two different ways of processing data streams, which belong to Java's standard IO library and NIO library respectively. The following is a detailed comparison of these two concepts:
Stream is part of the Java standard IO (i.e. blocking IO) model, which provides a way to read and write data sequentially. Stream is divided into two types: InputStream and OutputStream, which are used to read and write data respectively. These streams can be byte streams (such asInputStream
, OutputStream
) or a character stream (such asReader
, Writer
)。
Features:
close()
method to release resources. Starting with Java 7, the try-with-resources statement can automatically close the implementationAutoCloseable
Resources of the interface, including Stream.Channel is part of the Java NIO (New IO) model, which provides a higher level of abstraction than Stream, allowing more efficient processing of data. Channels can be bidirectional, meaning they can be used to read and write data. The main Channel types includeFileChannel
、SocketChannel
、ServerSocketChannel
andDatagramChannel
。
Features:
Summarize
In Java, the I/O operation model can be classified based on two dimensions: synchronous/asynchronous and blocking/non-blocking.
definition:Synchronous blocking I/O is the most traditional I/O model. When a thread calls an I/O operation (such as read or write), the thread will be blocked until the operation is completed. This means that the thread cannot perform any other tasks before the operation is completed.
Features:
InputStream
、OutputStream
、Socket
andServerSocket
scene.Example:
Use traditionalInputStream
andOutputStream
Read and write files:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class SyncBlockingIOExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt")) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = fis.read(buffer)) != -1) {
fos.write(buffer, 0, bytesRead);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
definition: In synchronous non-blocking I/O, a thread will not be blocked after calling an I/O operation. If the operation cannot be completed immediately, the method will return immediately, usually returning a special value (such as -1 or 0) or throwing an exception to indicate that the operation was not completed.
Features:
Channels
andBuffers
, by callingconfigureBlocking(false)
Put the channel into non-blocking mode.Example:
Using NIOFileChannel
To perform non-blocking reading and writing:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
public class SyncNonBlockingIOExample {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("input.txt");
FileOutputStream fos = new FileOutputStream("output.txt");
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel()) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
inChannel.configureBlocking(false);
while (inChannel.read(buffer) > 0) {
buffer.flip();
outChannel.write(buffer);
buffer.clear();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
definition: Synchronous multiplexed I/O model usageSelector
(selector) to monitor multipleChannel
When the thread callsSelector.select()
, it will block until at least oneChannel
Events (such as readable, writable, connection request, etc.) occur.
Features:
Channel
, improving concurrency.Selector
andSelectionKey
Mechanism that can efficiently handle a large number of concurrent connections.Example:
Using NIOFileChannel
To perform non-blocking reading and writing:
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Set;
public class SyncMultiplexingIOExample {
public static void main(String[] args) throws IOException {
try (Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
serverSocketChannel.socket().bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
if (selector.select() > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
for (SelectionKey key : keys) {
if (key.isAcceptable()) {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel clientChannel = ssc.accept();
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ);
}
}
keys.clear();
}
}
}
}
}
definition: In the asynchronous non-blocking I/O model, a thread returns immediately after initiating an I/O operation without waiting for the operation to complete. When the operation is completed, the thread will be notified asynchronously through a callback function or event notification.
Features:
AsynchronousChannel
Interface and its subclass implementations, such asAsynchronousFileChannel
andAsynchronousSocketChannel
。Example:
Using NIOAsynchronousFileChannel
Perform asynchronous file reading and writing:
import java.io.IOException;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.ByteBuffer;
import java.util.concurrent.CountDownLatch;
public class AsyncNonBlockingIOExample {
public static void main(String[] args) throws IOException, InterruptedException {
AsynchronousFileChannel inChannel = AsynchronousFileChannel.open(Paths.get("input.txt"), StandardOpenOption.READ);
AsynchronousFileChannel outChannel = AsynchronousFileChannel.open(Paths.get("output.txt"), StandardOpenOption.WRITE);
ByteBuffer buffer = ByteBuffer.allocate(1024);
CountDownLatch latch = new CountDownLatch(1);
inChannel.read(buffer, 0, buffer, 0, (channel, result) -> {
buffer.flip();
outChannel.write(buffer, 0, buffer, 0, null);
latch.countDown();
});
latch.await();
inChannel.close();
outChannel.close();
}
}
Note: The asynchronous model requires support from the underlying operating system (Kernel)
definition: In theory, this model does not exist, because "asynchronous" means that the operation is performed in the background and the thread is not blocked. Therefore, asynchronous blocking I/O is a contradictory concept and does not appear in practice.
Choosing the right I/O model is critical to performance and resource management. In high-concurrency scenarios, synchronous non-blocking I/O or synchronous multiplexing I/O models are common choices, while in scenarios that require extreme performance and responsiveness, asynchronous non-blocking I/O models are preferred.
Zero-Copy Concept
Zero copy technology means that in the process of data transmission from one place to another, the data does not need to be copied between the user space and the kernel space, or at least the number of such copies is reduced, so as to improve the efficiency of the system. In traditional I/O operations, when data is read from the network or disk, it is first copied to the buffer of the kernel space, and then copied from the kernel space to the buffer of the user space. In contrast, in zero copy, data can be processed directly in the kernel space, or directly passed from the kernel space to the network device, thereby reducing the CPU copy operation, reducing system overhead, and improving the efficiency of data transmission.
The origin of zero copy
The concept of zero copy first appeared in operating system design, aiming to solve the performance bottleneck caused by data replication in traditional I/O operations. In early computer systems, all I/O operations required multiple data replications in user space and kernel space, which gradually became a performance bottleneck after high-speed networks and large-capacity disks became common.
Key technical points
Implementation in Java:
Java supports zero-copy technology through the NIO (New I/O) framework. NIO introducesFileChannel
andSocketChannel
They provide more efficient I/O operations. Specifically,FileChannel.transferTo()
andFileChannel.transferFrom()
Methods can transfer data directly from a file channel to a socket channel, or vice versa, without loading the data into a buffer, thus achieving zero copy.
For example, suppose you need to send the contents of a large file to the network. The traditional approach is to first read the file contents into a buffer and then write the contents of the buffer to the network. This involves two copy operations: one from the disk to the buffer and another from the buffer to the network.transferTo()
When using this method, data can be transferred directly from disk to network without the need for an intermediate buffer, which reduces the number of copies and achieves zero copy.
Let's take an example using ByteBuffer:
ByteBuffer
and otherBuffer
Class (such asCharBuffer
,ShortBuffer
etc.) provide buffers that can be filled or emptied without having to directly involve copying between user space and kernel space.ByteBuffer
Can be used directly or indirectly in zero-copy techniques:
ByteBuffer.allocateDirect(size)
CreatedByteBuffer
Instances are mapped directly to physical memory, bypassing the Java heap. When such a buffer is used withFileChannel
orSocketChannel
When used together, data can be transferred directly between physical memory and hardware devices without the need for additional copying through the Java heap. This can achieve true zero-copy on some platforms.FileChannel
oftransferTo()
andtransferFrom()
: These methods allow data to be directlyFileChannel
andSocketChannel
transmission between them without the need to passByteBuffer
Acts as an intermediary. This means that data can be transferred directly from disk to the network or vice versa without having to be copied between user space and kernel space.ByteBuffer
ofwrap()
method:wrap()
Method allows you to wrap an existing byte array or other buffer into aByteBuffer
, so that the data does not need to be copied to a new buffer. This is useful to avoid unnecessary data copying.ByteBuffer
ofslice()
method:slice()
method creates a view of the buffer without copying the underlying data. This means that a largeByteBuffer
Split into multiple smaller buffers without copying the data.Use ByteBuffer in conjunction with FileChannel:
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
public class ZeroCopyExample {
public static void main(String[] args) {
Path path = Path.of("example.txt");
try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
long transferred = fileChannel.transferTo(0, fileChannel.size(), System.out);
System.out.println("Transferred bytes: " + transferred);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Notice:
We should note that there is no such thing as zero copy. The zero copy mentioned here only refers to the fact that there is no user-level copy for our application itself. But even at the user level, it is impossible to completely eliminate the copy operation, but to minimize the copy operation. Therefore, we can understand that the term zero copy actually refers to the technology of reducing the number of data copies, not the real zero copy operation.