Thread state transition diagram
is non-blocking IO using multiple distribution methods
For example, your server makes a chat room, and you have to create a thread for each connection, because when you call like In.read (BUF), the thread blocks here. In the case of NIO, as long as the event is registered, it uses a reaction pattern, which is then dispatched when an IO event occurs, without waiting there.
The current distributed computing Web services are prevalent in the world, the bottom of these network service can not be separated from the operation of the socket. They all have a common structure:
1. Read Request
2. Decode Request
3. Process Service
4. Encode reply
5. Send Reply
The classic Web services are designed as shown in the following diagram, which completes the processing of data in each thread:
But this pattern will degrade very quickly as the user load increases. We need to find a new solution to keep the data flowing, obviously, the event-triggering mechanism is the best solution, when an event occurs, it triggers the handler and then starts processing the data.
The reactor pattern is similar to event handling in AWT:
Reactor Mode participants
1.Reactor is responsible for responding to IO events, which, when they occur, are sent to the corresponding handler to handle, which is similar to the AWT thread
2.Handler is responsible for non blocking behavior, similar to AWT actionlisteners, and is responsible for binding handlers to event events, similar to AWT addActionListener
As shown in figure:
Java NIO provides the basic mechanism of implementation for the reactor pattern, and its selector, when it finds that a channel has data, informs us by Slectorkey, where we implement the binding of events and handler.
Let's look at the reactor mode code:
Public class reactor implements runnable{Final Selector Selector; Final Serversocketchannel ServerSocket;
Reactor (int port) throws IOException { selector = Selector.open (); ServerSocket = Serversocketchannel.open (); Inetsocketaddress address = new Inetsocketaddress (Inetaddress.getlocalhost (), port); Serversocket.socket (). bind (address);
Serversocket.configureblocking (FALSE); Register the channel with the selector Selectionkey SK =serversocket.register (selector,selectionkey.op_accept);
Logger.debug ("-->start serversocket.register!");
Use SK's attache function to bind acceptor if there is something that triggers acceptor Sk.attach (New acceptor ()); Logger.debug ("-->attach" (New Acceptor ()); } public void Run () {//normally in a new Thread try { while (! Thread.interrupted ()) { Selector.select (); Set selected = Selector.selectedkeys (); Iterator it = Selected.iterator (); Selector The following traversal occurs if a channel is found to have op_accept or read events. while (It.hasnext ()) An event triggers a accepter thread for the first time Trigger Socketreadhandler later Dispatch ((Selectionkey) (It.next ())); Selected.clear (); } }catch (IOException ex) { Logger.debug ("Reactor stop!") +EX); } }
Run Acceptor or Socketreadhandler void Dispatch (Selectionkey k) { Runnable r = (Runnable) (K.attachment ()); if (r!= null) { R.run (); } } Class Acceptor implements Runnable {//inner public void Run () { try { Logger.debug ("-->ready for accept!"); Socketchannel C = serversocket.accept (); if (c!= null) Call handler to handle channel New Socketreadhandler (selector, c); } catch (IOException ex) { Logger.debug ("Accept stop!") +EX); } } } }
|
The above code cleverly uses the Socketchannel attach feature to link hanlder and channel that can occur, triggering the handler of the corresponding link when an event occurs.
And look at the handler code:
| public class Socketreadhandler implements Runnable { public static Logger Logger = Logger.getlogger (Socketreadhandler.class); Private Test test=new test (); Final Socketchannel socket; Final Selectionkey SK;
static final int READING = 0, sending = 1; int state = READING; Public Socketreadhandler (Selector sel, Socketchannel c) Throws IOException { socket = C; Socket.configureblocking (FALSE); SK = Socket.register (sel, 0); Bind Selectionkey to this handler the run method of this class will be invoked when an event is triggered next. Refer to dispatch (Selectionkey K) Sk.attach (this);
The Selectionkey is also marked as readable so that it can be read. Sk.interestops (Selectionkey.op_read); Sel.wakeup (); } public void Run () { try{ Test.read (Socket,input); Readrequest (); }catch (Exception ex) { Logger.debug ("Readrequest error" +ex); } } /** * Processing Read data * @param key * @throws Exception */ private void Readrequest () throws Exception {
Bytebuffer input = bytebuffer.allocate (1024); Input.clear (); try{ int bytesread = Socket.read (input); ...... Activate the thread pool to process these request RequestHandle (New Request (SOCKET,BTT)); ..... }catch (Exception e) { }
}
|
Notice that a attach is executed in the handler, so that, covering the front of the acceptor, the next time the Read event occurs, the handler will trigger the handler directly. Thus the process of reading and writing the data is processed.
After the data is read out, you can make them into a thread pool so that when the data is read out, it is immediately thrown into the thread pool, which speeds up processing:
Further, we can use multiple selector to handle connection and read events separately.
A high-performance Java Network Service mechanism is to be formed, exciting cluster parallel computing is about to be implemented.
Http://www.jdon.com/concurrent/reactor.htm
--------------
Java NiO non-blocking applications are commonly used in the areas of I/O reading and writing, as we know, the performance bottlenecks of the system are usually in I/O read and write, including for ports and files, in the past, after opening an I/O channel, read () will be waiting to read byte content on the side of the port, if no content comes in, Read () is also silly and so on, which will affect our program to continue to do other things, then the improvement is to open the thread, let the thread to wait, but this is also very resource-intensive.
Java NiO non-blocking technology is actually taking the reactor mode, or observer mode for us to monitor the I/O port, if the content comes in, will automatically notify us, so that we do not have to open a number of threads Deng, from the outside, to achieve a smooth I/O read and write, not blocked.
The advent of Java NiO is not just a technical performance improvement, you'll find it everywhere on the web, because it's a milestone, Starting with JDK1.4, Java has started to improve performance-related functionality, making it possible for Java to run alongside languages such as C or Perl in the underlying or parallel distributed computing operations.
If you still doubt the performance of Java, your ideas and ideas are completely outdated, Java a year or two should be defined with a new noun. Starting from JDK1.5 to provide support for new performance, such as threading, concurrency, Java applications in the game and other timely areas of the opportunity has matured, Java in the stability of its middleware status, began to encroach on the traditional C field.
This article briefly introduces the basic principles of NIO, and in the next article, it will be discussed in depth with an article in the reactor model and the famous thread master Doug Lea.
The main principle and application of NIO.
NIO has a major class selector, which resembles an observer, as long as we tell selector what needs to be socketchannel, we go on to do something else, and when something happens, he informs us and returns a group of Selectionkey, We read these keys, we get the socketchannel we just registered, and then we read the data from the channel, and we can be sure that the package will read, and then we'll be able to process the data.
Selector internal principle is actually doing a registered channel polling access, constant polling (currently on this algorithm), once the poll to a channel something registered, such as the data came, he will stand up and report, hand over a key, Let's use this key to read the channel content.
Understanding this basic principle, we combine code to look at use, in use, also in two directions, one is threading, one is using not threading, the latter is relatively simple, look at the following code:
Import java.io.*; Import java.nio.*; Import java.nio.channels.*; Import java.nio.channels.spi.*; Import java.net.*; Import java.util.*;/** * * @author Administrator * @version */
public class Nbtest { /** creates new nbtest * * Public Nbtest () { }
public void StartServer () throws Exception { int channels = 0; int nkeys = 0; int currentselector = 0;
Using Selector Selector Selector = Selector.open ();
Establish channel and bind to port 9000 Serversocketchannel SSC = Serversocketchannel.open (); Inetsocketaddress address = new Inetsocketaddress (Inetaddress.getlocalhost (), 9000); Ssc.socket (). bind (address);
The way to set the non-blocking. Ssc.configureblocking (FALSE); Register channel with selector and events of interest to us Selectionkey s = ssc.register (selector, selectionkey.op_accept); Printkeyinfo (s); while (true)//constant polling { Debug ("nbtest:starting select");
Selector The Select method informs us that the events we are interested in have occurred. Nkeys = Selector.select (); If something happens to us, it returns a value greater than 0. if (Nkeys > 0) { Debug ("Nbtest:number of keys after select operation:" +nkeys);
Selector returns a group of Selectionkeys We get the channel we just registered from the channel () method in the key. Set Selectedkeys = Selector.selectedkeys (); Iterator i = Selectedkeys.iterator (); while (I.hasnext ()) { s = (Selectionkey) i.next (); Printkeyinfo (s); Debug ("Nbtest:nr Keys in Selector:" +selector.keys (). Size ());
When a key is processed, it is removed from the READY keyword (ready keys) List I.remove (); if (s.isacceptable ()) { Get the channel we just registered from channel (). Socket socket = ((Serversocketchannel) S.channel ()). Accept (). socket (); Socketchannel sc = Socket.getchannel ();
Sc.configureblocking (FALSE); Sc.register (Selector, Selectionkey.op_read | Selectionkey.op_write); System.out.println (++channels); } Else { Debug ("Nbtest:channel not acceptable"); } } } Else { Debug ("Nbtest:select finished without any keys."); } }
} private static void Debug (String s) { System.out.println (s); }
private static void Printkeyinfo (Selectionkey SK) { string s = new string ();
s = "Att:" + (sk.attachment () = null? " No ": yes"); S + + ", Read:" + sk.isreadable (); S + + ", Acpt:" + sk.isacceptable (); S + + ", cnct:" + sk.isconnectable (); S + + ", Wrt:" + sk.iswritable (); S + + ", Valid:" + sk.isvalid (); S + + ", Ops:" + sk.interestops (); Debug (s); } /** * @param args the command line arguments */ public static void Main (String args[]) { Nbtest nbtest = new Nbtest (); Try { Nbtest.startserver (); } catch (Exception e) { E.printstacktrace (); } }
} |
This is an example of a noblock server waiting on port 9000, if we are working on a client program, we can interact with it, or use telnet hostname 90000 to link to it.
By carefully reading this routine, I believe you have a general understanding of the principle and use of NIO, the next one, we will use multithreading to deal with this data, and then build their own reactor mode.
Http://www.jdon.com/concurrent/nio%D4%AD%C0%ED%D3%A6%D3%C3.htm