Eric Bruno

Dr. Dobb's Bloggers

Increase Java Serialization Performance

July 30, 2013

The simplest way to send and receive a Java object is to use an ObjectOutputStream/ObjectInputStream object pair, but is it the most efficient way? Let's experiment.

Working with Java network IO is fairly straightforward. You use a combination of ServerSocketInputStream and OutputStream objects, and then send data back and forth between two Java applications or Java Threads. The simplest way to send and receive a Java object is to use an ObjectOutputStream/ObjectInputStream object pair, but is it the most efficient way? Let's experiment.

Java Network IO Summary

First, let's review the basics of Java network IO. To begin, you need to create a ServerSocket that sits and waits for network clients to connect. A client can be any application, even a C++ application, so long as it connects on the correct IP address and port. Here's an example you can add to any Java code to create a connection listener (get the complete code listing here):

In this code, a Thread is created and started, and the work is done in the run() method. The first step is to create a ServerSocket on the localhost where 8081 is the port to listen on. You can use any port; I arbitrarily chose 8081. Next, a call to accept() blocks and waits until a network client connects on the matching IP address and port. The return is a Socket connection to the client that's used to communicate with the client. In this code, I instantiate a Listener object, which is a class I wrote to encapsulate all network communication, and add it to a collection of listeners. This code is wrapped in a while loop so that the ServerSocket will always be there ready to accept each incoming connection. Next, let's dive into the actual network communication.

Using ObjectOutputStream

Before we look at the Listener class (introduced in the code snippet above), let's look at the Sender class I wrote that takes a Java object and sends it over the network to any clients connected:

The Sender class extends Thread and calls Thread.start() in the constructor, which means each Sender object instantiated will result in a new running thread. Within the run() method, the first step is to create a connection to the server (the code that created the ServerSocket above) on the write IP address and port. Next, the resulting Socket's OutputStream object is retrieved via a call to Socket.getOutputStream(), and passed into the constructor of an ObjectOutputStream object.

If you look closely, you'll see there's a BufferedOutputStream object in there as well. Although it's not required, using buffered IO improves efficiency and performance, as an application can write to the underlying output stream without necessarily invoking a call to the underlying system for each byte written. Later, we'll examine the performance differences with and without it.

An object can be written by simply calling ObjectOutputStream.writeObject(), followed by a call to flush() to force the bytes to be sent out over the network. In the complete sample application, included below, the Sender code will send 100,000 Message objects — an arbitrary number — in order to measure the time it takes to send and receive them.

Using ObjectInputStream

On the flip side, the Listener object uses ObjectInputStream to listen and reconstruct Java Objects as they arrive, as shown here:

As with Sender, this class extends Thread, which results in a new running thread with each object instantiated. If you recall, this class was instantiated when a network client connects to the ServerSocket, with the resulting Socket connection passed into the constructor. Within the run() method, the Socket's InputStream is retrieved, and passed into the constructor of ObjectInputStream. Again, we use buffered IO (BufferedInputStream in this case) for efficiency and performance. To read an Object as it's sent, a call is made to ObjectInputStream.readObject(), which blocks until a complete object arrives over the network.

This is very straightforward, and the actual code behind sending and receiving entire Java Objects is minimal. In fact, most of the code in this example involves setting up the network connections. It's important to note that any Objects sent via Java IO must be serializable, which is achieved by implementing the java.io.Serializable interface. This interface doesn't contain any methods or fields; merely its presence is enough. Here's the Message class used in this example:

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!