preface

Only a bald head can be strong

To recap:

  • Explain the agency model to your girlfriend
  • The packaging pattern is as simple as that

Originally I expected to review the traditional IO pattern first, the traditional IO pattern of the relevant classes (because there are many classes).

However, I found that there were many excellent articles in the process of sorting out, and I might not reach their level if I sorted out them by myself. And while traditional IO is expected to be used, NIO is not.

Here are a few mind maps that I think are well organized (source addresses are provided below for you to read) :

Classification structure drawing according to operation mode:

Byte stream input and output comparison diagram:

Character stream input and output comparison diagram:

Structure diagram of classification by operation object:

The original address of the above picture is @Xiaoming, the author of Zhihu:

  • zhuanlan.zhihu.com/p/28286559

There are also excellent articles reading traditional IO source code:

  • Blog.csdn.net/panweiwei19…

I believe you read the above two links + understand the packaging mode is so simple, the traditional IO should be nothing ~~

However, NIO is quite strange to me, and I was exposed to it when I was studying. Nio is available in jdk1.4 and is superior to traditional IO.

I believe that many beginners like me, NIO is not very understanding. We now have JDK10 released, jdK1.4 niO does not know, it is a little unreasonable.

So I spent a few days getting to the heart of NIO, looking at the NIO modules of Ideas for Java Programming and Crazy Java Handouts. However, I will find that I am still very confused after reading it. I do not know what NIO is used for, and the information on the Internet does not correspond well with the knowledge points in the book.

  • There is a lot of material on the web that explains NIO based on the five IO models, and there are many concepts involved in the five IO models:Synchronous/asynchronous/blocking/non-blocking/multiplexing.And different people have different ways of understanding.
  • And Unixselect/epoll/poll/pselect.fdThese keywords, without the relevant basis of people seem to be a mystery
  • This leads to the belief that NIO is far out of reach in the beginning

In the process of looking for materials, I also collected a lot of materials to explain NIO. This article is to understand NIO from a beginner’s perspective. It is also a summary of my two days of watching NIO.

  • I hope you can see what NIO is, what is the core knowledge of NIO, can use NIO~

So let’s get started. If there are any mistakes in this article, please feel free to correct them in the comments section

Disclainer: This article uses JDK1.8

I. Overview of NIO

The new Java I/O library introduced in the java.nio.* package in JDK 1.4 is intended to increase speed. In fact, the “old” I/O packages have been reimplemented using NIO, and we can benefit even if we don’t explicitly program in NIO.

  • Nio is a non-blocking IO and a new IO

I was concerned when I read in Java Programming Minds that “even if we don’t explicitly program with NIO, we can benefit from it.” So we tested the performance of copying files using NIO versus traditional IO:


import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class SimpleFileTransferTest {

    private long transferFile(File source, File des) throws IOException {
        long startTime = System.currentTimeMillis();

        if(! des.exists()) des.createNewFile(); BufferedInputStream bis =new BufferedInputStream(new FileInputStream(source));
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(des));

        // Write what the data source reads to the destination -- using arrays
        byte[] bytes = new byte[1024 * 1024];
        int len;
        while((len = bis.read(bytes)) ! = -1) {
            bos.write(bytes, 0, len);
        }

        long endTime = System.currentTimeMillis();
        return endTime - startTime;
    }

    private long transferFileWithNIO(File source, File des) throws IOException {
        long startTime = System.currentTimeMillis();

        if(! des.exists()) des.createNewFile(); RandomAccessFile read =new RandomAccessFile(source, "rw");
        RandomAccessFile write = new RandomAccessFile(des, "rw");

        FileChannel readChannel = read.getChannel();
        FileChannel writeChannel = write.getChannel();


        ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024);/ / 1 m buffer

        while (readChannel.read(byteBuffer) > 0) {
            byteBuffer.flip();
            writeChannel.write(byteBuffer);
            byteBuffer.clear();
        }

        writeChannel.close();
        readChannel.close();
        long endTime = System.currentTimeMillis();
        return endTime - startTime;
    }

    public static void main(String[] args) throws IOException {
        SimpleFileTransferTest simpleFileTransferTest = new SimpleFileTransferTest();
        File sourse = new File("F:\\ movie \\[movie Paradise www.dygod.cn] Guess train -cd1.rmvb");
        File des = new File("X:\\Users\\ozc\\Desktop\\io.avi");
        File nio = new File("X:\\Users\\ozc\\Desktop\\nio.avi");

        long time = simpleFileTransferTest.transferFile(sourse, des);
        System.out.println(time + ": Ordinary byte stream time");

        long timeNio = simpleFileTransferTest.transferFileWithNIO(sourse, nio);
        System.out.println(timeNio + ": NIO time"); }}Copy the code

I tested the file sizes of 13M, 40M and 200M respectively:

1.1 Why NIO

It can be seen that the traditional IO reimplemented with NIO is not fake at all, and the effect is better than NIO in large files (of course, personal several times, may not be very accurate).

  • NIO has a learning cost and is not as easy to understand as traditional IO.

So does this mean we can stop using/learning NIO?

The answer is no. IO operations are often used in two situations:

  • File IO
  • Network IO

The charm of NIO: Use IO in the network can be reflected!

  • Later, we will talk about using NIO in the network

NIO quick start

First let’s look at the differences between IO and NIO:

  • It can be simply considered as:IO is stream-oriented processing and NIO is block-oriented (buffer) processing
    • Stream-oriented I/O systems process data one byte at a time.
    • A block-oriented (buffer) I/O system processes data as blocks.

NIO consists of three core components:

  • Buffer the buffer
  • The Channel pipe
  • The Selector Selector

2.1 Buffer buffers and Channels

NIO does not process data as streams, but as buffers and channels.

To put it simply:

  • A Channel is a railroad, a buffer is a train

And our NIO is through the Channel pipeline to store the Buffer Buffer Buffer to achieve data processing!

  • Keep in mind that a Channel does not deal with data, it only transports it. It is the Buffer Buffer that deals with the data
    • Channel – > transport
    • Buffer – > data

In contrast to traditional IO, flows are one-way. For NIO, with the concept of Channel pipeline, our reading and writing are two-way (trains on the railway can go from Guangzhou to Beijing, and naturally can return from Beijing to Guangzhou)!

2.1.1 Buffer Core points of buffer

Let’s take a look at what’s interesting about the Buffer Buffer.

Buffers are abstract classes for buffers:

Of these, ByteBuffer is the most used implementation class (reading and writing bytes in a pipe).

What do we do when we get a buffer? Simply read/write data to the buffer. So, the core method of buffering is:

  • put()
  • get()

The Buffer class maintains four core variable attributes to provide information about the array it contains. They are:

  • Capacity of the Capacity
    • The maximum number of data elements a buffer can hold. The capacity is set when the buffer is created and can never be changed. (It can’t be changed because it’s an array.)
  • The upper bound Limit
    • The total amount of data in the buffer represents how much data is currently in the buffer.
  • Position the Position
    • The location of the next element to be read or written. Position is automatically defined by the correspondingget( )andput( )Function update.
  • Mark Mark
    • A memo location. Used to record the last read/write position.

2.1.2 Buffer code demo

First, show how the buffer is created and how the value of the core variable changes.


    public static void main(String[] args) {

        // Create a buffer
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);

        // Take a look at the initial values of the four core variables
        System.out.println("Initial -->limit-- >"+byteBuffer.limit());
        System.out.println("Initial -->position-- >"+byteBuffer.position());
        System.out.println("Capacity -->capacity-- >"+byteBuffer.capacity());
        System.out.println("Initial -->mark-- >" + byteBuffer.mark());

        System.out.println("-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --");

        // Add some data to the buffer
        String s = "Java3y";
        byteBuffer.put(s.getBytes());

        // Take a look at the initial values of the four core variables
        System.out.println("After putting -->limit-- >"+byteBuffer.limit());
        System.out.println("After putting -->position-- >"+byteBuffer.position());
        System.out.println("After put -->capacity-- >"+byteBuffer.capacity());
        System.out.println("After you put it --> Mark -->" + byteBuffer.mark());
    }
Copy the code

Running results:

Now I want to get data from the cache, how do I get it? NIO gives us the flip() method. This method changes position and limit!

Once again, let’s flip() and see what happens to the values of the four core attributes:

It is obvious that:

  • Limit is now position
  • And position becomes 0

When filp() is called, limit is the limit of where to read, and position is the limit of where to read

Normally we call filp() ** “switch to read mode” **

  • Called whenever data is to be read from the cachefilp()“Switch to Read mode”.

After switching to read mode, we can read data from the buffer:


        // Create a limit() size byte array (because only limit is readable)
        byte[] bytes = new byte[byteBuffer.limit()];

        // Load the read data into our byte array
        byteBuffer.get(bytes);

        // Output data
        System.out.println(new String(bytes, 0, bytes.length));

Copy the code

Then print the value of the core variable to see:

After reading, we want to write data to the buffer, so we use the clear() function, which “clears” the buffer:

  • The data isn’t really wiped out, it’s just forgotten

2.1.3 Key points of a FileChannel Channel

Channel A Channel that transmits data but does not directly manipulate data. Manipulating data is done through the Buffer Buffer!


        // 1. Obtain the channel through local I/O
        FileInputStream fileInputStream = new FileInputStream("F:\\3yBlog\\JavaEE \\Elasticsearch is that simple. Md");

        // Get the input channel of the file
        FileChannel inchannel = fileInputStream.getChannel();

        // 2. After jdk1.7, the static method.open() is used to obtain channels
        FileChannel.open(Paths.get("F:\\3yBlog\\JavaEE \\Elasticsearch"), StandardOpenOption.WRITE);
Copy the code

Use FileChannel with buffer to copy files:

Use memory map file to implement file copy function (direct operation buffer) :

Transfer () is used to transfer data between channels (direct operation buffer) :

2.1.4 Direct and Indirect buffers

  • Indirect buffers need to go through a copy phase (copy from kernel space to user space).
  • The direct buffer does not need to go through the copy stage and can also be understood as a memory mapped file (the image above also shows an example).

There are two ways to use the direct buffer:

  • When a buffer is created, it is allocated a direct buffer
  • Called on FileChannelmap()Method to map files directly into memory for creation

2.1.5 Scatter and Gather and Character set

I feel I don’t use this knowledge enough, but there are a lot of tutorials about this knowledge, I also use it to say:

  • Scatter reads: Reads data in one channel into multiple buffers
  • Gather write: To write a collection of data from multiple buffers into a single channel

Scattered read

Gather to write

Character set (as long as the encoding and decoding formats are the same, it’s ok)

Iii. IO model understanding

To better understand NIO, let’s take a look at the IO model

According to the classification of I/O models by UNIX network programming, there are five I/O models in UNIX:

  • Blocking I/O
  • Non-blocking I/O
  • I/O multiplexing
  • Signal drives I/O
  • Asynchronous I/O

3.0 Learn the basics of the I/O model

3.0.1 File descriptor

The Linux kernel treats all external devices as one file. Read and write operations on a file call system commands (apis) provided by the Linux kernel, and return a file descriptor (FD). Read/write to a socket also has a response descriptor, called a socket fd (Socket file descriptor). The descriptor is a number that points to a structure in the kernel (file path, data area, etc.).

  • So, in Linux, operations on files are implemented using file descriptors.

3.0.2 User space and kernel space

In order to ensure that user processes cannot directly operate the kernel and ensure the security of the kernel, the system divides the virtual space into two parts

  • Part of it is kernel space.
  • Part of it is user space.

3.0.3I/O Running Process

Let’s see how IO works in a system (let’s take read as an example)

As you can see, when an application calls the read method, it waits to retrieve data from kernel space and copy the data from kernel space to user space.

  • This waiting is a necessary process!

Here are just three of the most commonly used I/0 models:

  • Blocking I/O
  • Non-blocking I/O
  • I/O multiplexing

3.1 Blocking I/O model

Recvfrom is called in process (user) space, and its system call does not return until the packet arrives and is copied to the buffer of the application process or an error occurs, during which time it waits.

3.2 Non-blocking I/O model

When recvFROM from the application layer to the kernel, an EWOULDBLOCK error is returned if there is no data, and the non-blocking I/O model is generally polled for this state to see if the kernel has any data coming.

3.3I/O Multiplexing model

In Linux, operations on files are implemented using file descriptors.

Under Linux it implements the I/O reuse model like this:

  • callselect/poll/epoll/pselectOne of the functions,Multiple file descriptors are passed inIf there is a file descriptorWhen ready, returnOtherwise, block until timeout.

Int poll(struct pollfd * FDS,nfds_t NFDS, int timeout);

The pollfd structure is defined as follows:


struct pollfd {
    int fd;         /* File descriptor */
    short events;         /* Waiting event */
    short revents;       /* What actually happened */
};

Copy the code

  • (1) When a user process calls select, the entire process will be blocked;
  • (2) At the same time, the kernel “monitors” all select-responsible sockets;
  • (3) When the data in any socket is ready, the select returns;
  • (4) At this time, the user process calls the read operation to copy the data from the kernel to the user process (space).
  • So, I/O multiplexing is characterized by a mechanism whereby a process can wait for multiple file descriptors at the same time, and select() returns when any one of these file descriptors is read ready.

The advantage of select/epoll is not that it can process individual connections faster, but that it can process more connections.

3.4 SUMMARY of I/O Model

I’ve given you all the proper descriptions, but I don’t know if you understand. Here are a few examples to summarize the three models:

Blocking I/O:

  • Java3y and his girlfriend went to buy tea. They waited in line for a long time and finally got to order a drink. I’d like green research, please. But happy tea is not something you can order and get right away, so II waited an hour at the gate of Xi Cha to get itGreen research.
    • Wait at the door for an hour

Non-blocking I/O:

  • Java3y and his girlfriend went to buy a little, and finally waited in line for a long time to order a drink. I’ll have the boob milk tea, please. But a little bit is not an order that can be taken immediately,At the same timeThe waiter told me: You will have to wait about half an hour. So Java3y and his girlfriend went to play a few doudizhu, feeling almost time. soAsk a little moreA: Excuse me, is it my turn? My tracking number is XXX. The waiter told Java3y: Not yet, the order number is XXX, you have to wait for a while, you can go to play around. After asking for several times, I finally got my boob milk tea.
    • Went to the street, fight the landlord, from time to time to ask me no

I/O Multiplexing model:

  • Java3y went to McDonald’s to eat hamburgers with his girlfriend. Now he can use wechat mini program to order food. So I sat down with my girlfriend and ordered my food. After ordering dinner, play a game of landlord and chat.From time to time I heard the radio repeating XXX please take your mealAnyway, my number hasn’t arrived yet, so just keep playing. ~ ~Just wait until you hear the announcement. Time passed quickly, then came Java3y, please come and get your food. So I can get my chili wings burger.
    • Listen to the radio. The radio isn’t for me alone. I’m on the radio. I’ll just go get it.

4. Use NIO to complete network communication

4.1NIO fundamentals continue to explain

Back to our original diagram:

NIO is called no-blocking IO, which is also blocking for the FileChannel.

We’ve only been looking at FileChannel, and there are several channels for our network communication

So: we use NIO mostly on the Internet, and most of the discussion on the Internet is based on network communication! Saying NIO is non-blocking NIO is also embodied in the network!

And you can see from the diagram above that there’s also a Selector, a Selector, something like that. As we’ve said from the beginning, the core elements of NIO are:

  • Buffer the Buffer
  • The Channel tunnel
  • The Selector Selector

Our use of NIO in networks tends to be a multiplexing model of the I/O model!

  • The analogy of a Selector is McDonald’s radio.
  • A thread can manage the state of multiple channels

4.2NIO Blocking mode

To better understand this, let’s write the NIO status code for blocking in the network, and then see how non-blocking is written to make it easier to understand.

  • If it blocks, you don’t have a Selector, you just use Channel and Buffer.

Client:


public class BlockClient {

    public static void main(String[] args) throws IOException {

        // 1. Obtain the channel
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1".6666));

        // 2. Send an image to the server
        FileChannel fileChannel = FileChannel.open(Paths.get("X:\ Users\ ozc\ Desktop\ New folder \\1.png"), StandardOpenOption.READ);

        // 3. To use NIO, you must have a Buffer, which works with data
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 4. Read the local file (picture) and send it to the server
        while(fileChannel.read(buffer) ! = -1) {

            // Always switch to read mode before reading
            buffer.flip();

            socketChannel.write(buffer);

            // Switch to write mode to allow the pipeline to continue reading the file's data
            buffer.clear();
        }

        // 5. Close the streamfileChannel.close(); socketChannel.close(); }}Copy the code

Server:


public class BlockServer {

    public static void main(String[] args) throws IOException {

        // 1. Obtain the channel
        ServerSocketChannel server = ServerSocketChannel.open();

        // 2. Get the file channel, write the image from the client to the local project (write mode, no create)
        FileChannel outChannel = FileChannel.open(Paths.get("2.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

        // 3. Bind links
        server.bind(new InetSocketAddress(6666));

        // 4. Get the client connection (blocked)
        SocketChannel client = server.accept();

        // 5. To use NIO, you must have a Buffer, which deals with data
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 6. Save the image sent by the client to the local directory
        while(client.read(buffer) ! = -1) {

            // Always switch to read mode before reading
            buffer.flip();

            outChannel.write(buffer);

            // Switch to write mode to allow the pipeline to continue reading the file's data
            buffer.clear();

        }

        // 7. Close the channeloutChannel.close(); client.close(); server.close(); }}Copy the code

The result is to save the image from the client locally:

When the server saves the image, it wants to tell the client that the image has been received:

The client receives data from the server:

If only the above code is not good! The program will block!

  • Because the server does not know whether the client still has data to send (unlike at the beginning, the client sends data after the stream is closed, the server can know that the client has no data to send), the server keeps reading the data sent by the client.
  • This leads to a blockage!

Therefore, when the client finishes writing data to the server, it explicitly tells the server that it has finished sending data!

4.3NIO non-blocking form

If we use non-blocking mode, then we can not explicitly tell the server that we have finished sending data. Let’s see how to write:

Client:

public class NoBlockClient {

    public static void main(String[] args) throws IOException {

        // 1. Obtain the channel
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1".6666));

        // 1.1 Switches to non-blocking mode
        socketChannel.configureBlocking(false);

        // 2. Send an image to the server
        FileChannel fileChannel = FileChannel.open(Paths.get("X:\ Users\ ozc\ Desktop\ New folder \\1.png"), StandardOpenOption.READ);

        // 3. To use NIO, you must have a Buffer, which works with data
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 4. Read the local file (picture) and send it to the server
        while(fileChannel.read(buffer) ! = -1) {

            // Always switch to read mode before reading
            buffer.flip();

            socketChannel.write(buffer);

            // Switch to write mode to allow the pipeline to continue reading the file's data
            buffer.clear();
        }

        // 5. Close the streamfileChannel.close(); socketChannel.close(); }}Copy the code

Server:


public class NoBlockServer {

    public static void main(String[] args) throws IOException {

        // 1. Obtain the channel
        ServerSocketChannel server = ServerSocketChannel.open();

        // 2. Switch to non-blocking mode
        server.configureBlocking(false);

        // 3. Bind the connection
        server.bind(new InetSocketAddress(6666));

        // 4. Get the selector
        Selector selector = Selector.open();

        // 4.1 Register the channel with the selector, specifying to receive "listen channel" events
        server.register(selector, SelectionKey.OP_ACCEPT);

        // 5. Rotate to get "ready" events on the selector --> as long as select()>0, it is ready
        while (selector.select() > 0) {
            // 6. Get all registered "select keys" of the current selector (ready listener events)
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            // 7. Get the "ready" event, (different events do different things)
            while (iterator.hasNext()) {

                SelectionKey selectionKey = iterator.next();

                // The receive event is ready
                if (selectionKey.isAcceptable()) {

                    // 8. Obtain the client link
                    SocketChannel client = server.accept();

                    // 8.1 Switches to the non-blocking state
                    client.configureBlocking(false);

                    --> Get client connection to read channel data (listen for readready event)
                    client.register(selector, SelectionKey.OP_READ);

                } else if (selectionKey.isReadable()) { // The read event is ready

                    // 9. Get the channel for the current selector readready state
                    SocketChannel client = (SocketChannel) selectionKey.channel();

                    // 9.1 Reading data
                    ByteBuffer buffer = ByteBuffer.allocate(1024);

                    // 9.2 Get the file channel, write the image passed by the client to the local project (write mode, no create)
                    FileChannel outChannel = FileChannel.open(Paths.get("2.png"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);

                    while (client.read(buffer) > 0) {
                        // Always switch to read mode before reading
                        buffer.flip();

                        outChannel.write(buffer);

                        // Switch to write mode to allow the pipeline to continue reading the file's databuffer.clear(); }}// 10. Cancel select key (already handled event, should cancel)iterator.remove(); }}}}Copy the code

After saving the image, the server tells the client that the image has been received.

On the server, just write some data to the client:

On the client side, to get data from the server side, you also need to register (listen for read events)!


public class NoBlockClient2 {

    public static void main(String[] args) throws IOException {

        // 1. Obtain the channel
        SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1".6666));

        // 1.1 Switches to non-blocking mode
        socketChannel.configureBlocking(false);

        // 1.2 Get the selector
        Selector selector = Selector.open();

        // 1.3 Register the channel with the selector to get the data returned by the server
        socketChannel.register(selector, SelectionKey.OP_READ);

        // 2. Send an image to the server
        FileChannel fileChannel = FileChannel.open(Paths.get("X:\ Users\ ozc\ Desktop\ New folder \\1.png"), StandardOpenOption.READ);

        // 3. To use NIO, you must have a Buffer, which works with data
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        // 4. Read the local file (picture) and send it to the server
        while(fileChannel.read(buffer) ! = -1) {

            // Always switch to read mode before reading
            buffer.flip();

            socketChannel.write(buffer);

            // Switch to write mode to allow the pipeline to continue reading the file's data
            buffer.clear();
        }


        // 5. Rotate to get "ready" events on the selector --> as long as select()>0, it is ready
        while (selector.select() > 0) {
            // 6. Get all registered "select keys" of the current selector (ready listener events)
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

            // 7. Get the "ready" event, (different events do different things)
            while (iterator.hasNext()) {

                SelectionKey selectionKey = iterator.next();

                // 8. The read event is ready
                if (selectionKey.isReadable()) {

                    // get the corresponding channel
                    SocketChannel channel = (SocketChannel) selectionKey.channel();

                    ByteBuffer responseBuffer = ByteBuffer.allocate(1024);

                    // 9. It is known that the server will return the data in response to the client, and the client will receive it here
                    int readBytes = channel.read(responseBuffer);

                    if (readBytes > 0) {
                        // Switch the read mode
                        responseBuffer.flip();
                        System.out.println(new String(responseBuffer.array(), 0, readBytes)); }}// 10. Cancel select key (already handled event, should cancel)iterator.remove(); }}}}Copy the code

Test results:

Here’s a quick summary of the key points when using NIO:

  • Registers a Socket channel with a Selector to listen for events of interest
  • When the time of interest is ready, it goes into our processing method
  • Delete the select key each time we finish processing the ready event (because we are done)

4.4 Pipes and DataGramChannel

I’m not going to talk about TCP anymore, but UDP is pretty easy.

UDP:

The pipe:

Five, the summary

Generally speaking, NIO is also an important knowledge point, because it is the basis of learning NetTY ~

It’s obviously impossible to cover NIO in a single article, but you can follow the links below to learn more about IT

References:

  • www.zhihu.com/question/29… — How to learn Java NIO?
  • Ifeve.com/java-nio-al… –Java NIO series tutorials
  • www.ibm.com/developerwo… — — — — — the NIO primer
  • Blog.csdn.net/anxpp/artic… —–Linux Network I/O model
  • Wangjingxin. Top / 2016/10/21 /… —– talk about NIO and AIO for Java
  • www.yiibai.com/java_nio/—–Java NIO tutorial
  • Blog.csdn.net/cowthan/art… ——Java 8: The New IO for Java (NIO)
  • Blog.csdn.net/youyou15437… ——-JAVA NIO(1. Basic Concepts, basic classes)
  • www.cnblogs.com/zingp/p/686… —–I/O mode and I/O multiplexing
  • www.cnblogs.com/Evsward/p/n… —- Master NIO, Procedural Life
  • Blog.csdn.net/anxpp/artic… —-Java Network IO programming summary (BIO, NIO, AIO with complete example code)
  • Zhuanlan.zhihu.com/p/24393775?… — Java newbie on the move
  • Ideas for Java Programming
  • Crazy Java Handouts

If the article has the wrong place welcome to correct, everybody exchanges with each other. Students who are used to reading technical articles on wechat and want to get more Java resources can follow the wechat public account :Java3y.

Article table of Contents navigation:

  • Zhongfucheng.bitcron.com/post/shou-j…