| By Steven Schwell | Article Rating: |
|
| February 1, 1998 12:00 AM EST | Reads: |
9,256 |
Implementation of a fixed size pool of Objects in a distributed application must consider problems caused by the unpredictable nature of remote connections. An implementation is presented here for Java's Remote Method Invocation, which takes advantage of the Distributed Garbage Collector to solve those problems.
You're probably familiar with the mechanism of a fixed size pool of Objects, in the context of a memory management system, that keeps memory in a fixed size buffer pool. The idea is to manage the use of a scarce resource by requiring Objects to be checked out of and into a pool. When all Objects are checked out, the pool is empty; clients cannot check out any more, until a claimed one is checked back in. When a client is done with an Object, it is expected to check the Object back into the pool so that other clients may claim it.
Aside from memory management, you could use an Object Pool of this sort to manage any scarce resource, or limit the number of concurrent users of a service or data structure. For example, you could use an ObjectPool as the basis of a simple license enforcement scheme which would limit the number of concurrent users of a service. As another example, you could use it to limit the number of concurrent visitors in a chat room application.
In a simple, non-remote Java applet or application, implementation of a fixed size ObjectPool would be fairly straightforward, as long as you can follow the rule that clients must check objects back into the pool when they are done with them. The ObjectPool needs only to keep a fixed size Vector of Objects, and parcel them out as requested until no more are left.
The requirement that Objects be returned to the pool when a client is done with them could be problematic in large applications where the end of an Object's usefulness could occur in many different places, far removed from where it was checked out of the pool. The problem is analogous to memory management in systems without garbage collection. It quickly becomes onerous to live up to your responsibility of checking the memory, or in this case, the Object from the ObjectPool, back in.
One idea is to do garbage collection on Objects from the ObjectPool, leveraging off of Java's own garbage collection mechanism. You could override the finalize() method of the Objects in the ObjectPool to check the Object back in when the Object is slated for garbage collection. In this way, the client needs only to remove references to the Object and rely on the local garbage collector to check the Object back into the pool.
The problem with that solution is that garbage collection in Java is, with good reason, not guaranteed to be timely. Garbage collection is expensive; the VM is free to do it only when necessary. Since garbage collection of Objects from the ObjectPool would rely on Java's garbage collection, it would be subject to the same vagaries. In many applications, the ObjectPool cannot wait indefinitely to reclaim its lost Objects. If your program does not use much memory, your unreferenced Objects may never get garbage collected, and the Objects would never get checked back into the ObjectPool.
An additional concern arises in a distributed application where the client may be in a different VM. What if contact with the client is broken before the client is able to check its Object back in to the server's pool? How can the pool reclaim that lost Object?
I present here an elegant solution to these problems for Java's Remote Method Invocation, which relies on RMI's Distributed Garbage Collector. In contrast to the local garbage collector, the DGC's behavior is well defined and reliable with respect to its timing. The DGC employs a lease mechanism for remote references. All remote references are leased to clients for a default period of ten minutes (which may be overridden by setting the java.rmi.dgc.leaseValue property). The client VM must request a new lease before the period runs out. Otherwise the server considers the remote reference to be dead and releases the corresponding remote Object to the local garbage collector for potential collection.
RMI also provides the java.rmi.server.Unreferenced interface, which remote Objects may implement to be notified when all remote references to the remote Object have been released. This includes the case when the last remote reference to a remote Object is released due to expiration of the lease. So taken together, Distributed Garbage Collection and the Unreferenced interface, give us just what we need to reclaim lost Objects from an ObjectPool.
Listing 1 shows an implementation of an ObjectPool that works for both remote clients and local clients. Even non-remote applications could benefit from this implementation because of its reliable garbage collection and reclamation of unreferenced Objects.
There are a few subtleties in the implementation that are worthy of elaboration. First of all, notice that remote Objects are created only as needed. This avoids the overhead of pre-allocating the Objects which may not all be needed every time the application is run.
Remote Objects are never released for local garbage collection; they are reused. This avoids the overhead of constantly creating new remote Objects every time an Object needs to be doled out. RMI calls the unreferenced() method every time the last remote reference to the remote Object is released; even multiple times on the same remote Object.
When an Object is checked back in, notice that the corresponding Object is taken from the 'out' Vector rather than the returned Object itself. This is because the returned Object may be only the stub for the remote Object, rather than the remote Object itself. Vector's indexOf()method uses the equals() method to find the Object in the array. Since the PoolObject is extended from UnicastRemoteObject, it inherits the implementation of equals() from RemoteObject which considers stubs to be equal to their corresponding remote Objects. In this way, I'm guaranteed to be reusing the remote Object itself rather than just its stub.
One other note: The PoolObject inner class is a remote Object and, as such, needs to be post-compiled by rmic to create its stub and skeleton classes. Running rmic on inner classes is a bit tricky because the name of the inner class is generated by javac and includes the '$'character. The '$' character must be quoted to make it to the rmic compiler. On some platforms, it must be quoted more than once. For example, on Solaris, the command line looks something like:
rmic ObjectPool\\\$PoolObject
Anticipated Patterns of Reuse
The PoolObject in the ObjectPool has no substance aside from the unreferenced() method. This is not a very interesting Object aside from its characteristics as an Object in a fixed size pool. Even so, in some circumstances, that may be all you need. If so, you can use the ObjectPool as is, or perhaps write an ObjectPoolIfc Remote interface so that ObjectPool can be accessed directly from RMI clients.
It is more likely, though, that you will need more interesting Objects to be in the fixed size pool. The implementation in listing 1 is not just an example of how you could write your own ObjectPools. It is intended for you to reuse the class exactly as it is to create your own ObjectPools. It is probably worth elaborating on this as an illustration of general techniques for class reuse.
In the design of any RMI system, you will be faced with the choice of passing Objects between VMs by value or by reference. Passing by value is accomplished by implementing the Serializable interface, and passing by reference is accomplished by implementing the Remote interface. A discussion of the tradeoffs in this design decision is beyond the scope of this article. For our purposes here, let's consider how to reuse ObjectPool for both cases, when the Object in the ObjectPool is to be passed by value and by reference.
If the Objects in your fixed size pool are to be remote Objects, i.e. passed by reference, you can subclass PoolObject to create that Object and subclass ObjectPool, overriding the newPoolObject() factory method to instantiate your PoolObject subclass. This is an example of the Template Method design pattern. The code would look something like listing 2.
If the Objects in your fixed size pool are to be Serializable, i.e. passed by value, you can reuse ObjectPool by composition. The PoolObject remote reference will be passed to the client as a remote Object when the PoolObject is serialized. That contained remote reference in the Serializable PoolObject is not visible to clients of the PoolObject. It is there solely to enable collection of lost PoolObjects by the DGC. The code would look something like listing 3.
Of course these are just some of the ways that ObjectPool and PoolObject can be reused. This is a maximally reusable and generally powerful little class that should be a welcome addition to your object-oriented Java arsenal.
References
Gamma, E., Johnson, R. & Vlissides, J. "Design Patterns: Elements of Object-Oriented Architecture" Addison-Wesley, Reading, MA, 1995.
Java Remote Method Invocation Specification, JavaSoft
Published February 1, 1998 Reads 9,256
Copyright © 1998 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
About Steven Schwell
Steven Schwell is a Senior Developer and Java Guru in the New York office of Micromuse, Inc., a leading provider of Service Level Management software. Steve is currently developing a number of large distributed Java apps. He holds a M.S. in Computer Science from Columbia University.
- Performance of Java Compilers: An Empirical Study
- Java Kicks Ruby on Rails in the Butt
- Ulitzer’s Amazing First 30 Days in Public Beta
- 1st Annual Government IT Expo: Call for Papers Deadline July 15
- REA Is Where RIA Becomes the Norm
- Why an Application Grid?
- Will Ulitzer Dominate News Content on The Web? -Gartner
- Clear Toolkit 4: The Road Map
- Profiling Netbeans within Amazon EC2
- Java Persistence on the Grid: Approaches to Integration
- Performance of Java Compilers: An Empirical Study
- Java Kicks Ruby on Rails in the Butt
- Developing Rich Client Applications Using Swing - II
- The Right Time for Real Time Java
- Xpress Suite Adds Automatic Java to iPhone Conversion
- Ulitzer’s Amazing First 30 Days in Public Beta
- Initial Thoughts on IBM Acquisition of Sun Microsystems
- 1st Annual Government IT Expo: Call for Papers Deadline July 15
- Maximizing Java Performance with Bespoke Programming
- REA Is Where RIA Becomes the Norm
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- The i-Technology Right Stuff
- JavaServer Faces (JSF) vs Struts
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- What's New in Eclipse?
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate





































