Introduction to Java NIO and high concurrency network programming implementation
Java NIO
NIO (Non-blocking I/O, non-blocking I/O) is a new set of I/O APIs introduced by Java in JDK 1.4, aiming to solve the problem of insufficient performance and scalability of traditional I/O (i.e. BIO, blocking I/O) in high concurrency scenarios.
Core features of NIO
Non-blocking I/O: Supports non-blocking mode, allowing threads to avoid waiting for I/O operations to complete, thereby improving system resource utilization.
Buffer: Reading and writing data through buffers, not directly through streams.
Selector: manages multiple channels through one thread, greatly improving the scalability and efficiency in high concurrency scenarios.
Multiplexing: The status of multiple channels can be monitored simultaneously through the Selector mechanism (such as connection ready, data readiness, etc.).
Comparison of BIO (blocking I/O) vs. NIO (non-blocking I/O)
characteristic | BIO | NIO |
---|---|---|
I/O mode | Blocking, the thread will wait for the I/O to complete | Non-blocking, threads do not need to wait for I/O to complete |
Threading model | One thread per connection | One thread manages multiple connections |
Applicable scenarios | Low concurrency, simple scenarios | High concurrency, network programming scenarios |
performance | High thread resource cost and poor scalability | More efficient resource utilization and better scalability |
Core components of NIO
(aisle)
Similar to Stream, but Channel supports both read and write.
Common Channels: SocketChannel, ServerSocketChannel, DatagramChannel, FileChannel.
(Buffer)
Data reading and writing are performed through a Buffer.
Common buffers: ByteBuffer, CharBuffer, IntBuffer, etc.
(Selector)
Core component used to listen for events in multiple channels, such as connection ready, read ready, write ready, etc.
Through multiplexing mechanism, one thread manages multiple channels.
Represents the registration relationship between the channel and the selector, including the event type of the channel (such as read, write, connect, etc.).
Java NIO Network High Concurrency Programming Example
Scene description
Server side: Listen to client requests, receive data and return information.
Client: Connect to the server, send data and receive responses.
Server-side code
import ; import ; import ; import ; import .*; import ; public class NioServer { public static void main(String[] args) { try { // 1. Create ServerSocketChannel for listening to client connections ServerSocketChannel serverChannel = (); (new InetSocketAddress(8080)); (false); // Set to non-blocking mode // 2. Create Selector and register ServerSocketChannel to listen for ACCEPT events Selector selector = (); (selector, SelectionKey.OP_ACCEPT); ("NIO Server started on port 8080..."); while (true) { // 3. Check whether any event occurs, block and wait if (() == 0) { continue; // If no event is ready, continue the loop } // 4. Get ready event collection Iterator<SelectionKey> keyIterator = ().iterator(); while (()) { SelectionKey key = (); (); // Remove the key currently processed to avoid repeated processing try { // 5. Handle different events if (()) { // Client connection event handleAccept(key, selector); } else if (()) { // Read client data events handleRead(key); } } catch (IOException e) { ("Error handling client connection: " + ()); (); // Cancel the error key if (() != null) { ().close(); } } } } } catch (IOException e) { (); } } // Handle ACCEPT events private static void handleAccept(SelectionKey key, Selector selector) throws IOException { ServerSocketChannel serverChannel = (ServerSocketChannel) (); SocketChannel clientChannel = (); // Accept client connections (false); // Set to non-blocking mode (selector, SelectionKey.OP_READ); // Register READ Events ("Client connected: " + ()); } // Handle READ events private static void handleRead(SelectionKey key) throws IOException { SocketChannel clientChannel = (SocketChannel) (); ByteBuffer buffer = (1024); int bytesRead; try { bytesRead = (buffer); // Read data from the channel } catch (SocketException e) { ("Connection reset by client: " + ()); (); (); return; } if (bytesRead > 0) { (); // Switch to read mode String message = new String((), 0, ()); ("Received from client: " + message); // Write back data to the client (); (("Echo: " + message).getBytes()); (); (buffer); } else if (bytesRead == -1) { // Client disconnect ("Client disconnected: " + ()); (); (); // Unregistered event } } }
Client Code
import ; import ; import ; import ; public class NioClient { public static void main(String[] args) throws IOException { // 1. Create SocketChannel Connection Server SocketChannel socketChannel = (); (false); if (!(new InetSocketAddress("127.0.0.1", 8080))) { // Wait for the connection to complete while (!()) { ("Connecting to server..."); } } ("Connected to the server"); // 2. Send data to the server String message = "Hello, NIO Server!"; ByteBuffer buffer = (()); (buffer); // 3. Receive data written back by the server (); int bytesRead = (buffer); if (bytesRead > 0) { (); String response = new String((), 0, ()); ("Received from server: " + response); } (); } }
Running results
Client output
Connected to the server
Received from server: Echo: Hello, NIO S
The process has ended, the exit code is 0
Server-side output
NIO Server started on port 8080...
Client connected: /127.0.0.1:50104
Received from client: Hello, NIO Server!
Connection reset by client: /127.0.0.1:50104
Key points of high concurrency in NIO
Non-blocking I/O: Selector can listen to multiple client connections at the same time, eliminating the need to create a thread for each connection, reducing thread overhead.
Multiplexing: Selector provides a multiplexing mechanism that can listen to multiple events at the same time (such as connection ready, read ready, etc.).
IO operation optimization: I/O operation is performed through ByteBuffer, which avoids frequent data copying of traditional streams and improves read and write efficiency.
Limitations and improvements of NIO
1. Limitations
The use of NIO is relatively complex and requires manual management of channels and buffers.
In high concurrency scenarios, the performance of Selector may become a bottleneck.
2. Direction of improvement
Netty: A high-performance networking framework based on NIO simplifies the use of NIO while providing higher throughput and scalability.
Asynchronous I/O (AIO): Java NIO 2.0 (introduced in JDK 7) provides asynchronous I/O, further optimizing thread resource utilization.
Applicable scenarios and suggestions
Applicable scenarios: highly concurrent network applications, such as web servers, message push services; I/O-intensive applications.
Recommended usage: For complex high-performance network applications, it is recommended to use mature frameworks such as Netty to avoid directly manipulating the underlying code of NIO.
The above is a detailed article that will help you understand how Java can implement high concurrency programming in network NIO. For more information about Java network NIO, please pay attention to my other related articles!