| | A few obvious additions in Merlin have received most of the press so far, including the XML parser, secure sockets extension, and 2D graphics enhancements. This article introduces an exciting new API many have overlooked. The new I/O (input/output) packages finally address Java's long-standing shortcomings in its high-performance, scalable I/O. The new I/O packages -- java.nio.* -- allow Java applications to handle thousands of open connections while delivering scalability and excellent performance. These packages introduce four key abstractions that work together to solve the problems of traditional Java I/O: | The complier interprets the asterisk character, *, as a wildcard character -- a character that represents all files in the current directory when java runs -- instead of an asterisk symbol. As such, the command line arguments passed to calculator are not 4, *, and 3. Instead, the command line arguments are 4, a list of file names for all files in the directory from where java runs, and 3. To fix that problem, surround the asterisk with double-quote characters (e.g., java calculator 4 "*" 3). | In this article, I will focus on tuning IO performance. Many applications spend much of their runtime on network or file IO, and poorly performing IO code can run many times slower than well-tuned IO code. | Standard I/O is a standardized input/output mechanism that originates from the Unix operating system. Although this mechanism is mostly used with older non-GUI operating systems, standard I/O still plays a role in modern GUI (graphical user interface) operating systems, where people use it to debug malfunctioning programs and to teach input/output in entry-level programming courses. | Before giving an example of a handshake sequence, it is necessary to explain the NEED_TASK status. During handshake, the SSL/TLS protocol often needs to perform operations that block or that take a long time to complete. In most situations, this corresponds to the generation of session keys, but in more complex scenarios, it may involve asking for a password from the user or validating a certificate with a remote server. In non-blocking IO models, these operations cannot be performed in the same thread that is used to service IO requests, since it would block all other connections serviced by that thread. Therefore, the SSLEngine supports a mechanism to delegate these tasks to external threads. When such a lengthy task must be performed, the NEED_TASK status is returned. The developer must then call the method SSLEngine.getDelegatedTask() to obtain an instance of Runnable that encapsulates the task and then executes it in the most suitable way. Some of the more common possibilities are executing it synchronously in the IO thread, or asynchronously, either in a thread pool or in a new thread. The following code shows how to execute the tasks in a separate thread using the new java.util.concurrent package: | This article reviewed JDK I/O streams, which should give you a good understanding of how to program with them. Remember, there are many I/O stream classes in the java.io package, so if you plan to use streams in your programs, it would be worth your while perusing the JDK 1.2 API documentation about the java.io package. You might also find the Java Tutorial helpful. | This article discusses and illustrates a variety of techniques for improving Java I/O performance. Most of the techniques center around tuning disk file I/O, but some are applicable to network I/O and window output as well. The first set of techniques presented below cover low-level I/O issues, and then higher-level issues such as compression, formatting, and serialization are discussed. Note, however, the discussion does not cover application design issues, such as choice of search algorithms and data structures, nor does it discuss system-level issues such as file caching. | | This article discusses the concept of writing specialized stream classes that can process (filter) data in a special fashion. Note, this is an advanced topic on I/O streams and assumes the reader has some knowledge of how I/O streams work. For the basics of I/O stream programming, the difference between byte and character streams, and the concept of stream chaining, please refer to Programming with Java I/O Streams. | The challenge with Scatter/Gather I/O is that using memory scattered over multiple blocks is not a trivial matter. On projects (on Windows platforms) in the 1990s, I tended to use a custom COM stream implementation from my company's proprietary libraries, which was implemented for a different task some years previously. Permit me to talk about the COM stream architecture for a moment. (I know I promised in the last chapter there would be no more COM, but there is a point to this, even for UNIX diehards. Trust me, I'm a doctor!) | Alan Bateman: The first NIO specification was JSR 51, New I/O APIs for the Java Platform, led by Mark Reinhold. It was delivered into JDK 1.4, and that API put in the basis for NIO in Java, focusing on buffers, channels, and charsets. JSR 51 delivered the first piece of the scalable socket I/Os into the platform, providing a non-blocking, multiplexed I/O API, thus allowing the development of highly scalable servers without having to resort to native code. | In this section, we will propose a solution to the challenge of designing a portable framework for the Proactor and Reactor I/O patterns. To demonstrate this solution, we will transform a Reactor demultiplexor I/O solution to an emulated async I/O by moving read/write operations from event handlers inside the demultiplexor (this is "emulated async" approach). The following example illustrates that conversion for a read operation: | Three new functions have been added to the Java Native Interface (JNI) to support direct buffers. For information, see JNI Enhancements in v 1.4. | 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. | The new input/output (NIO) library, introduced with JDK 1.4, provides high-speed, block-oriented I/O in standard Java? code. This hands-on tutorial covers the NIO library in great detail, from the high-level concepts to under-the-hood programming detail. You'll learn about crucial I/O elements like buffers and channels, and examine how standard I/O works in the updated library. | With Java 2 Platform Standard Edition (J2SE) 1.4 came numerous changes to the Java platform's I/O handling capabilities. Instead of just the previous J2SE releases' continual support for stream-based I/O operations with chaining from stream to stream, Merlin adds new capabilities in what is dubbed the New I/O classes (NIO), which now reside in the java.nio package. | Therefore, most of what you have previously learned about manipulating ByteBuffer objects, (such as getting different views of a ByteBuffer object), also applies to MappedByteBuffer objects. | Java 1.4 introduced the "New I/O" API's (JSR-51 http://jcp.org/en/jsr/detail?id=51) which provided an improved, faster and more efficient interface to I/O operations on sockets and files. This JSR is an extension of the original and aims to complete the feature set described in the original JSR. Notably, this JSR intends to implement a new and improved File System interface, support for asynchronous I/O operations on files and sockets and the completion of the New I/O socket functionality as described in the original JSR. | In this lesson, I will show you how to do memory-mapped IO for data records containing mixed types of data. I will also show you how to manipulate memory maps using view buffers such as FloatBuffer. | The package java.io has two major parts: character streams and byte streams. Characters are 16-bit UTF-16 characters, whereas bytes are (as always) 8 bits. I/O is either text-based or data-based (binary). Text-based I/O works with streams of human-readable characters, such as the source code for a program. Data-based I/O works with streams of binary data, such as the bit pattern for an image. The character streams are used for text-based I/O, while byte streams are used for data-based I/O. Streams that work with bytes cannot properly carry characters, and some character-related issues are not meaningful with byte streams—though the byte streams can also be used for older text-based protocols that use 7- or 8-bit characters. The byte streams are called input streams and output streams, and the character streams are called readers and writers. For nearly every input stream there is a corresponding output stream, and for most input or output streams there is a corresponding reader or writer character stream of similar functionality, and vice versa. | Notice the pattern that Copy's source code uses when working with files. First, because Copy is designed to copy byte-oriented streams instead of character-oriented streams, Copy declares a pair of FileInputStream and FileOutputStream reference variables, and initializes those variables to null. Within a Try statement, Copy attempts to create FileInputStream and FileOutputStream objects. The FileInputStream constructor throws a FileNotFoundException object if it cannot locate the source file and the FileOutputStream constructor throws an IOException object if it is given bad path information to a destination file. Assuming both constructors succeed, a While loop statement repeatedly calls FileInputStream's read() method to read the next byte, and FileOutputStream's write() method to write that byte. The read() method continues to read bytes until end-of-file is encountered. At that time, read() returns -1, and the loop ends. Regardless of whether or not an exception is thrown, the Finally clause executes last. By using If decision statements, it checks that FileInputStream and FileOutputStream objects were created. If one or both of those objects was created, the object's close() method is called to close the underlying file. Because close() throws an IOException object if the underlying file is not open, it is necessary to place close() method calls within their own Try statements. If you follow a pattern similar to what you have just read, you should not experience trouble when working with the file stream classes. |
|