Country / Region [Select] Terms of Use
All of dw ----------------- DB2 EServer Lotus Rational Tivoli WebSphere ---------------- AUTONOMIC Computing Grid Computing Java Technology Linux Open Source Power Architecture SOA & Web Services Web Architecture Wireless XML ----------------- DW forums ----------------- DW Subscription ---------------- AlphaWorks ---------------- All of IBM
Home Products Services & Solutions Support & Downloads My Account
DeveloperWorks> Java Technology>
Merlin Brings Nonblocking I / O to the Java Platform
CONTENTS:
I / O Programming Before Merlinthe Reactor Patternchannels and SELECTORSABRACADABRA - NONBLOCKING I / O! ConclusionResourcesDownloadabout The Authorsrate this Article
Related content:
Java Design Patterns 101Java Sockets 101magic with merlin series
Subscriptions:
DW Newslettersdw Subscription (CDS and Downloads)
New Addition Greatly Reduces Thread Overhead
Level: Intermediate
Aruna Kalagnanam
(kaaruna@in.ibm.com), Software Engineer, IBM
Balu G
(gbalu@in.ibm.com), Software Engineer, IBM01 Mar 2002
The Java technology platform is long overdue for a nonblocking I / O mechanism. Fortunately, Merlin (JDK 1.4) has a magic wand for almost every occasion, and unblocking blocked I / O is this magician's specialty. Software engineers Aruna Kalagnanam and Balu G introduce The Nonblocking Features of Merlin's New I / O Package, Java.Nio (NIO), and Employ a socket-programming Example to show you just what nio can do.
A server's ability to handle numerous client requests within a reasonable time is dependent on how effectively it uses I / O streams. A server that caters to hundreds of clients simultaneously must be able to use I / O services concurrently. Until JDK 1.4 (aka Merlin ), the Java platform did not support nonblocking I / O calls. With an almost one-to-one ratio of threads to clients, servers written in the Java language were susceptible to enormous thread overhead, which resulted in both performance problems and lack of scalability. to address this issue, a new set of classes have been introduced to the Java platform with the latest release. Merlin's java.nio package is chock full of tricks for resolving thread overhead, the most important being the new SelectableChannel and Selector classes. A CHANNEL REPRESENTS A MEANS OF A SERVER. A Selector is analogous to a windows message loop, in which the selector captures the various events from Different Clients and dispatches them to their respective event handlers. In this article, we'll show you how these two classes function together to create a nonblocking I / O mechanism for the Java platform. I / O programming before MerlinWe'll start with a look at a . basic, pre-Merlin server-socket program In the lifetime of a ServerSocket class, the important functions are as follows: Accept incoming connections Read requests from clients Service those requests Let's take a look at each of these steps using code snippets to illustrate. First, WE CREATE A New Serversocket:
Serversocket S = New Serversocket ();
NEXT, WEANT TO Accept An Incoming Call. A Call to Accept () Should Do The Trick Here, But There's A Little Trap You Have To Watch for: Socket Conn = S.Accept ();
The call to accept () blocks until the server socket accepts a client request for connection. Once a connection is established, the server reads the client requests, using LineNumberReader. Because LineNumberReader reads data in chunks until the buffer is full, the call blocks on A Read. The Following Snippet Shows LinenumberReader In Action (Blocks and ALL).
InputStream in = conn.getinputstream ();
InputStreamReader Rdr = New InputStreamReader (in);
LINENUMBERREADER LNR = New LinenumberReader (RDR);
Request Req = new request ();
While (! REQ.IsComplete ())
{
String s = lnr.readline ();
Req.addline (s);
}
InputStream.read () is another way to read data. Unfortunately, the read method also blocks until data is available, as does the write method. Figure 1 depicts the typical workings of a server. The bold lines represent blocking operations. Figure 1. A typical server in action Prior to JDK 1.4, liberal use of threads was the most typical way of getting around blocking But this solution created its own problem -.. namely thread overhead, which impacts both performance and scalability With the arrival of Merlin and the java.nio package, however, everything has changed. In the sections that follow, we'll look at the foundations of java.nio, and apply some of what we've learned to revising the server-socket example described above then. The Reactor patternThe principal force behind the design of NIO is the Reactor design pattern. Server applications in a distributed system must handle multiple clients that send them service requests. Before invoking a specific service, however, the server application must demultiplex and dispatch each incoming request to its corresponding service provider. The Reactor pattern serves precisely this function. It allows event-driven applications to demultiplex and dispatch service requests, which are then delivered concurrently to an application from one or more clients.Core Functions of the Reactor Pattern
Demultiplexing events Dispatching events to their corresponding event handlers The Reactor pattern is closely related to the Observer pattern in this aspect:. All dependents are informed when a single subject changes The Observer pattern is associated with a single source of events, however, whereas the Reactor pattern is associated with multiple sources of events. See Resources to learn more about the Reactor pattern. channels and SelectorsNIO's nonblocking I / O mechanism is built around selectors and channels. A Channel class represents a communication mechanism between a server and a client. In keeping with the Reactor pattern, a Selector class is a multiplexor of Channels. It demultiplexes incoming client requests and dispatches them to their respective request handlers. We'll look closely at the respective functions of the Channel class and the Selector class, and at how the Two Work to create a Nonblocking I / O Implementation. What The Channel Doesa Channel Repesents An open connection to an entity such as NIO channels can be asynchronously closed and interrupted a hardware device, a file, a network socket, or a program component that is capable of performing one or more distinct I / O operations, such as reading or writing. . So, if a thread is blocked in an I / O operation on a channel, another thread can close that channel. Similarly, if a thread is blocked in an I / O operation on a channel, another thread can interrupt that blocked thread. Figure 2. Class Hierarchy for Java.Nio.Channels As Figure 2 shows
re mainly concerned with the java.nio.channels.SocketChannel and java.nio.channels.ServerSocketChannel interfaces. These channels can be treated as replacements for java.net.Socket and java.net.ServerSocket, respectively. Channels can be used in a blocking or a nonblocking mode, though of course we will focus on using channels in nonblocking mode. Creating a nonblocking channelWe have two new classes to deal with in order to implement basic nonblocking socket read and write operations. These are the InetSocketAddress class from the java .net package, which specifies where to connect to, and the SocketChannel class from the java.nio.channels package, which does the actual reading and writing operations. The code snippets in this section show a revised, nonblocking approach to creating a basic server -Socket Program. Note The Changes Between Sample Samples and Those Used In The First Example, Starting With The Additional Our Two New Classes: String Host = ...;
Inetsocketaddress socketaddress = new inetsocketaddress (Host, 80);
Socketchannel Channel = SocketChannel.Open ();
Channel.connect (socketaddress);
The role of the bufferA is an abstract class that contains data of a specific primitive data type. It is basically a wrapper around a fixed-size array with getter / setter methods that make its contents accessible. The Buffer class has a number of subclasses, As Follows:
ByteBuffer CharBuffer DoubleBuffer FloatBuffer IntBuffer LongBuffer ShortBuffer ByteBuffer is the only class that supports reading and writing from and to the other types, since the other classes are type specific. Once connected, data can be read from or written to the channel with a ByteBuffer object. See Resources to Learn More About The bytebuffer. To make the channel Nonblocking, We call ConfigureBlockingmethod (False) on the channel, as shown here: Channel.configureBlockingMethod (false);
In blocking mode, a thread will block on a read or a write until the operation is completely finished. If during a read, data has not completely arrived at the socket, the thread will block on the read operation until all the data is available. In nonblocking mode, the thread will read whatever amount of data is available and return to perform other tasks. If configureBlockingMethod () is passed true, the channel's behavior will be exactly the same as that of a blocking read or write on a Socket. The one major difference, mentioned above, is that these blocking reads and writes can be interrupted by other threads. The Channel alone is not enough to create a nonblocking I / O implementation. A Channel class must work in conjunction with the Selector class to achieve nonblocking I / O. What the Selector doesThe Selector class plays the role of a Reactor in the Reactor pattern scenario. The Selector multiplexes events on several SelectableChannels. Each Channel registers events with the Selec .. Tor When events arrive from clients, the Selector demutliplexes them and dispatches the events to the corresponding Channels The simplest way to create a Selector is to use the open () method, as shown below:
Selector selector = Selector.open (); Channel meets SelectorEach Channel that has to service client requests must first create a connection The code below creates a ServerSocketChannel called Server and binds it to a local port:.
ServersocketChannel ServerChannel = ServersocketChannel.Open ();
ServerChannel.configureBlocking (False);
Inetaddress IA = inetaddress.getlocalhost ();
Inetsocketaddress isa = new inetsocketaddress (IA, port);
ServerChannel.Socket (). Bind (ISA);
Each Channel that has to service client requests must next register itself with the Selector A Channel should be registered according to the events it will handle For instance, a Channel that accepts incoming connections should be registered as shown here..:
SelectionKey AcceptKey =
Channel.Register (Selector, SelectionKey.op_Accept);
A Channel's Registration with the selectionKey Object. A KEY IS VALID Until ONE The Thse Three Conditions IS Met:
The Channel is closed. The Selector is closed. The Key itself is cancelled by invoking its cancel () method. The Selector blocks on the select () call. It then waits until a new connection is made, another thread wakes it up, or Another Thread Interrupts The Original Blocked Thread. Registering The ServerServer Is The Serversocketchannel That Registers Itself with The Selector To Accept All Incoming Connections, AS Shown Here:
SelectionKey AcceptKey = ServerChannel.Register (SEL, SelectionKey.op_Accept);
While (AcceptKey.Selector (). SELECT ()> 0) {
......
After the server is registered, We iterate through one one based on Its Type. After a key is processed, it is removed from the list of ready keys, as shown here:
Set readyKeys = SEL.SelectedKeys (); item it = readyKeys.Item ();
While (it.hasnext ())
{
SelectionKey Key = (SelectionKey) IT.Next ();
it.remove ();
....
....
....
}
If the key is acceptable, the connection is accepted and the channel is registered for further events such as read or write operations If the key is readable or writable, the server indicates it is ready to read or write data on its end.:
SocketChannel Socket;
IF (Key.isacceptable ()) {
System.out.println ("Acceptable Key");
ServersocketChannel SSC = (ServersocketChannel) Key.Channel ();
Socket = (socketchannel) ssc.accept ();
Socket.configureblocking (false);
SelectionKey Another =
Socket.Register (SEL, SelectionKey.op_read | SelectionKey.op_write);
}
IF (Key.IsReadable ()) {
System.out.println ("Readable Key");
String Ret = ReadMessage (key);
IF (Ret.Length ()> 0) {
WriteMessage (socket, re);
}
}
IF (key.iswritable ()) {
System.out.println ("Writable Key");
String Ret = ReadMessage (key);
Socket = (socketchannel) key.channel ();
IF (Result.Length ()> 0) {
WriteMessage (socket, re);
}
}
! Abracadabra - nonblocking server socket appear The final part of this introduction to nonblocking I / O in JDK 1.4 is left to you: running the example In this simple nonblocking server-socket example, the server reads a file name sent from the client. , Displays the File Contents, And Writes The Contents Back to The Client. Here's What You need to do to run the example:
Install JDK 1.4 (see Resources). Copy both source files onto your directory. Compile and run the server as java NonBlockingServer. Compile and run the client as java Client. Input the name of a text or java file in the directory where the class files are present. The server will read the file and send its contents to the client. The client will print out the data received from the server. (Only 1024 bytes will be read since that is the limit of the ByteBuffer used.) Close the client . by entering the command to quit or shutdown ConclusionThe new I / O packages from Merlin cover a broad scope The major advantage of Merlin's new nonblocking I / O implementation is twofold:. threads no longer block on reads or writes and the Selector is able to handle multiple connections, greatly reducing server application overhead. We have highlighted these two primary advantages of the new java.nio package. We hope that you will apply what you've learned here to your real-time application development eff Orts. Resources
Download the source files to run the example for this article. Install JDK 1.4. Learn about all the new nonblocking I / O APIs on the NIO home page. For a more general introduction to JDK 1.4, see the Java 2 platform, Standard Edition, v1.4 overview. See the Java Community Process to learn about the process by which the java.nio package became part of the Java platform. For an in-depth discussion of the Java platform's long-standing problem with thread overhead, see Allen Holub's proposal for fixing the Java platform's threading problems, including a section on Java I / O (developerWorks, October 2000). Learn more about the ByteBuffer class. If you want to learn about design patterns, take "Java design patterns 101" (developerWorks, January 2002). Get more information on the Reactor pattern. If you want to learn more about socket programming, try "Java sockets 101" (developerWorks, August 2001). John Zukowski's Magic with Merlin series is all about the changes Merlin brings to th e Java platform. The JavaWorld article "Master Merlin's new I / O classes" tells you how to get maximum performance out of nonblocking I / O and memory-mapped buffers. You'll find hundreds of articles about every aspect of Java programming in the DeveloperWorks Java Technology Zone. Downloadname
Size
Download Method
J-JAVAIO.ZIP
FTP
Information About Download Methods
About the authorsAruna Kalagnanam is a software engineer with e-Business Integration Technologies, IBM India Labs. You can contact Aruna at kaaruna@in.ibm.com. Balu G is a software engineer with e-Business Integration Technologies, IBM India Labs. Balu May Be Reached At Gbalu@in.ibm.com.
DeveloperWorks> Java Technology> About IBM | Privacy | Terms of Use | Contact