This is the 9th day of my participation in Gwen Challenge

This article is participating in “Java Theme Month – Java Development in Action”, see the activity link for details

An important interface and two abstract classes

In NIO, there is one interface and two abstract classes that we need to focus on, channels, buffers, and selectors

1.Channel

A Channel is similar to a stream, except that a Channel is two-way (the direction of the data can be changed by transferTo() or transferFrom()))

Interface source code

public interface Channel extends Closeable {
	// The Channel interface has only two abstract methods
	// Check whether the function is enabled
    public boolean isOpen(a);
    // Close the channel
    public void close(a) throws IOException;

}
Copy the code

Main abstract class

These classes are still not implemented, their implementation is the class name followed by the Impl, if you want to explore further, look at the implementation class, I will only briefly explain their abstract class

  1. FileChannel

This is the file channel, the above code is also used to create the way will not say. The DatagramChannel is used to read and write data on the network through UDP. The DatagramChannel is used to read and write data on the network.

DatagramChannel ch = DatagramChannel.open();
Copy the code
  1. SocketChannel

A Socket is a Socket channel that can read and write data on the network through TCP.

SocketChannel ch = SocketChannel.open(); 
// You also need to bind an IP address to use it
Copy the code
  1. ServerSocketChannel

ServerSocketChannel is a ServerSocketChannel that listens for TCP connections. After a selector is registered, when the selector iterator traverses the corresponding ServerSocketChannel, It gets the SocketChannel created by ServerSocketChannel based on the SelectionKey and operates on it

2.Buffer

A Buffer is an object that creates a Buffer during NIO

Abstract class source code

The content is too much, simple and easy to understand I skipped

public abstract class Buffer {
    static final int SPLITERATOR_CHARACTERISTICS =
        Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
	// Invariants: mark <= position <= limit <= capacity
	// These four numbers are the key to the entire Buffer
    private int mark = -1;// The tag that can be used to trace back to the location of the tag
    private int position = 0;// The current position from which both read and write operations start
    private int limit;// The limit that reading and writing cannot exceed
    private int capacity;// The number of bytes that can be written depends on the implementation class. For example, IntBuffer can write up to capacity int
    long address;// address, this is the address pointing to the buffer

    Buffer(int mark, int pos, int lim, int cap) {       
        if (cap < 0)
            throw new IllegalArgumentException("Negative capacity: " + cap);
        this.capacity = cap;
        limit(lim);
        position(pos);
        if (mark >= 0) {
            if (mark > pos)
                throw new IllegalArgumentException("mark > position: ("+ mark + ">" + pos + ")");
            this.mark = mark; }}public final int capacity(a) {
        return capacity;
    }
    public final int position(a) {
        return position;
    }
    // This is a redefinition of position, if greater than limit or less than 0 error
    // If mark is greater than the new position, drop mark
    public final Buffer position(int newPosition) {
        if ((newPosition > limit) || (newPosition < 0))
            throw new IllegalArgumentException();
        position = newPosition;
        if (mark > position) mark = -1;
        return this;
    }
    public final int limit(a) {
        return limit;
    }
    // Redefine limit. If limit is greater than capacity or less than 0, an error is reported
    // If position is greater than the new limit, reposition to limit
    // If mark is greater than the new limit, discard it
    public final Buffer limit(int newLimit) {
        if ((newLimit > capacity) || (newLimit < 0))
            throw new IllegalArgumentException();
        limit = newLimit;
        if (position > limit) position = limit;
        if (mark > limit) mark = -1;
        return this;
    }
    public final Buffer mark(a) {
        mark = position;
        return this;
    }
    // Reposition position to mark
    public final Buffer reset(a) {
        int m = mark;
        if (m < 0)
            throw new InvalidMarkException();
        position = m;
        return this;
    }
    // Switch to write mode
    public final Buffer clear(a) {
        position = 0;
        limit = capacity;
        mark = -1;
        return this;
    }
    // Switch to read mode
    public final Buffer flip(a) {
        limit = position;
        position = 0;
        mark = -1;
        return this;
    }
    // This can also be used to switch to read mode, but limit is not changed
    public final Buffer rewind(a) {
        position = 0;
        mark = -1;
        return this;
    }
    public final int remaining(a) {
        return limit - position;
    }
    public final boolean hasRemaining(a) {
        return position < limit;
    }
    // Implement the following functions:
    // Returns whether the buffer is readable only
    public abstract boolean isReadOnly(a);
    // Implement the following functions:
    // Returns whether the buffer is a readable array
    public abstract boolean hasArray(a);
    // Implement the following functions:
    // If the array of the buffer buffer is not only readable, return an array
    public abstract Object array(a);
    // Implement the following functions:
    // If the array of the buffer is not readable only, return the address of the array
    public abstract int arrayOffset(a);
    // Implement the following functions:
    // Determine whether the buffer is a direct buffer, i.e. stored in physical memory rather than in the JVM
    public abstract boolean isDirect(a);
    final int nextGetIndex(a) {                          
        if (position >= limit)
            throw new BufferUnderflowException();
        return position++;
    }
    // Move position back nb
    final int nextGetIndex(int nb) {                    
        if (limit - position < nb)
            throw new BufferUnderflowException();
        int p = position;
        position += nb;
        return p;
    }
    // Only the exception thrown is different
    // The top is an overflow exception, and the bottom is an overflow exception
    final int nextPutIndex(a) {                         
        if (position >= limit)
            throw new BufferOverflowException();
        return position++;
    }
    final int nextPutIndex(int nb) {                    
        if (limit - position < nb)
            throw new BufferOverflowException();
        int p = position;
        position += nb;
        return p;
    }
    // Check whether position can be positioned on I
    final int checkIndex(int i) {                       
        if ((i < 0) || (i >= limit))
            throw new IndexOutOfBoundsException();
        return i;
    }
    // Check whether position can be positioned on I + NB
    final int checkIndex(int i, int nb) {              
        if ((i < 0) || (nb > limit - i))
            throw new IndexOutOfBoundsException();
        return i;
    }
    final int markValue(a) {                            
        return mark;
    }
    / / to empty
    final void truncate(a) {                            
        mark = -1;
        position = 0;
        limit = 0;
        capacity = 0;
    }
    final void discardMark(a) {                         
        mark = -1;
    }
    // Check whether the starting position, length and size meet the requirements
    static void checkBounds(int off, int len, int size) { // package-private
        if ((off | len | (off + len) | (size - (off + len))) < 0)
            throw newIndexOutOfBoundsException(); }}Copy the code

Main abstract class

There are seven main abstract classes: ByteBuffer, CharBuffe, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer and ShortBuffer, which correspond to the basic data types respectively: Byte, char, double, float, int, long, short. They are also not implemented, and their implementation classes are more diversified, which I won’t go into here, but they all have the same functionality, but the corresponding data types are different

3.Selector

A Selector is called a Selector, also known as a multiplexer, and it’s the core component of the entire NIO. A Channel can register itself in a Selector () and set a SelectionKey, and then the Selector loops through the iterator of the SelectionKey, When a key is matched, the operation can be carried out, and the corresponding Channel can be obtained according to the SelectionKey.

graph LR
A[selector]  --> B((channel))
A --> C((channel))
A -->  D((channel))
A -->  E((channel))

Abstract class source code


public abstract class Selector implements Closeable {
    protected Selector(a) {}// This creates an instance of the Selector implementation class through the provider, the internal static object of the SelectorProvider
    // the last instance object is an instance of WindowsSelectorImpl
    public static Selector open(a) throws IOException {
        return SelectorProvider.provider().openSelector();
    }
    public abstract boolean isOpen(a);
	// Implement the following functions:
	// Returns a channel creator
    public abstract SelectorProvider provider(a);
    // Implement the following functions:
	// Returns the selector's keyset, which cannot be modified
    public abstract Set<SelectionKey> keys(a);
    // Implement the following functions:
	// Returns the selector's keyset, which can be modified
    public abstract Set<SelectionKey> selectedKeys(a);
	// Implement the following functions:
	// Start listening for channels and return 0 if no channels are ready
    public abstract int selectNow(a) throws IOException;
	// Implement the following functions:
	// Start listening for channels and set a timeout
    public abstract int select(long timeout)
        throws IOException;
	// Implement the following functions:
	// Start listening for channels
    public abstract int select(a) throws IOException;
    // Implement the following functions:
	// Wake up threads blocking on the SELECT method
	// in the implementation class WindowsSelectorImpl, there is an array of threads, which should be woken up
    public abstract Selector wakeup(a);
    public abstract void close(a) throws IOException;

}
Copy the code

The final implementation class is WindowsSelectorImpl

— — — — — — — — — — — — — — —

The more you know, the more you don’t know.

If you have any questions about the content of this article, please comment directly or email me. If you think my writing is good, a “like” is also a sign of support

Shall not be reproduced without permission!

Wechat search [programmer Xu Xiaobai], attention can be the first time to read the latest article. There are 50 high-frequency school recruitment interview questions prepared by me, as well as a variety of learning materials.