My name is Peter Steijn. I am an undergraduate at the University of Delaware, where I am working on an independent research project. I have been working on an optimization to object pooling upon which I have based a new object pool implementation -- GeneratorObjectPool. The following is about the implemented changes to how object pooling works.
Before I go any further I would like to thank my faculty mentor, Professor Phillip Conrad, for his insight and support. I would also like to thank apache contributor Sandy McArthur, who has spent the past few weeks discussing my ideas, providing guidance and looking over my [sometimes inane] attempts at coding. You can access my objects at: http://copland.udel.edu/~psteijn/apache/ *GeneratorObjectPool.java -- the object pool implementation *GeneratorObjectPoolFactory.java -- basically GeneralObjectPoolFactory *TestGeneratorObjectPool.java -- JUnit tests modified to work with GeneratorObjectPool, taken from TestGeneralObjectPool but modified because of some changed assumptions in how some methods work (addObject in particular). GeneratorObjectPool changes the behavior of object pooling in the borrowObject method. Previous object pooling implementations, when attempting to borrow an object from an empty pool, would create an object for the requestor; blocking until the object was created and then returning that object. This is especially inefficient for object pooling, where the objects you are creating are expected to be very expensive to create (read http://www.theserverside.com/news/thread.tss?thread_id=37146 for an argument on why you should only pool the heaviest of objects). For example, creation of a JDBC connection to a mysql database takes at least 25 milliseconds (with virtually 0 latency) and seconds in even a minimally latent network. In contrast to the creation of these objects, the act of borrowing, using and returning the objects to the pool by a requestor usually takes less time on the order of powers of ten. Using a JDBC connection for an average query can take as few as 5 milliseconds. Using other objects that don't involve sending data over a network would take even less time. The observation that I am leading up to is this: Most likely the objects that are loaned out, making the pool empty for your request (which is then going to sit there for up to seconds blocking while your object is being made) are going to come back far before the object you are creating would be ready. The difference in time between the first object that returns to the pool and when the requestor's object gets created is avoidable blocking time. In other words, we can save turn-around time on requests which is what object pooling is all about! GeneratorObjectPool does not block to create an object when a request hits an empty pool. Instead it schedules a TimerTask to run at the earliest time possible. This TimerTask creates an object and puts it into the pool. While the TimerTask is running, the requestor is looking for any object to return to the pool, not just the one that it asked to be created. This is done with a LinkedBlockingQueue (requires java 1.5.0_06 - there is a serious bug in LinkedBlockingQueue in previous 1.5 releases [ http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6215625], but I am also planning to implement a version of GeneratorObjectPool that can run on java 1.3). When hitting an empty object pool, the requestor should notice a very large performance increase. All other times the pool should not experience any performance degradation. Important issues to note: -you can no longer assume that an additional object is in the pool directly after calling the addObject method. addObject only schedules an object to be created and put into the pool. I feel that I have justified why this optimization is necessary. I look forward to constructive criticism and any discussion of my ideas. -Peter K. Steijn PS - I have not done performance testing on my implementation yet, and have only tested it on existing unit tests. This is just to introduce my ideas to the community. The code is in no way guaranteed to be robust code.
