Details
-
Improvement
-
Status: Closed
-
Minor
-
Resolution: Duplicate
-
1.4
-
None
Description
If no Object is in the pool the method GenericKeyedObjectPool.borrowObject(Object key) is blocking until a new Object (_factory.makeObject(key) ) is created. This will block all other threads even if they want an Object for a different key or want return an Object.
The GenericObjectPool.borrowObject() have a better implementation where the _factory.makeObject(key) is called after the synchronized block.
Could this changed like this?
GenericKeyedObjectPool.borrowObject(Object key)
public Object borrowObject(Object key) throws Exception { long starttime = System.currentTimeMillis(); for(;;) { ObjectTimestampPair pair = null; ObjectQueue pool = null; synchronized (this) { assertOpen(); pool = (ObjectQueue)(_poolMap.get(key)); if(null == pool) { pool = new ObjectQueue(); _poolMap.put(key,pool); _poolList.add(key); } // if there are any sleeping, just grab one of those try { pair = (ObjectTimestampPair)(pool.queue.removeFirst()); if(null != pair) { _totalIdle--; } } catch(NoSuchElementException e) { /* ignored */ } // otherwise if(null == pair) { // if there is a totalMaxActive and we are at the limit then // we have to make room if ((_maxTotal > 0) && (_totalActive + _totalIdle >= _maxTotal)) { clearOldest(); } // check if we can create one // (note we know that the num sleeping is 0, else we wouldn't be here) if ((_maxActive < 0 || pool.activeCount < _maxActive) && (_maxTotal < 0 || _totalActive + _totalIdle < _maxTotal)) { // allow new object to be created } else { // the pool is exhausted switch(_whenExhaustedAction) { case WHEN_EXHAUSTED_GROW: // allow new object to be created break; case WHEN_EXHAUSTED_FAIL: throw new NoSuchElementException(); case WHEN_EXHAUSTED_BLOCK: try { if(_maxWait <= 0) { wait(); } else { // this code may be executed again after a notify then continue cycle // so, need to calculate the amount of time to wait final long elapsed = (System.currentTimeMillis() - starttime); final long waitTime = _maxWait - elapsed; if (waitTime > 0) { wait(waitTime); } } } catch(InterruptedException e) { // ignored } if(_maxWait > 0 && ((System.currentTimeMillis() - starttime) >= _maxWait)) { throw new NoSuchElementException("Timeout waiting for idle object"); } else { continue; // keep looping } default: throw new IllegalArgumentException("whenExhaustedAction " + _whenExhaustedAction + " not recognized."); } } } pool.incrementActiveCount(); } // create new object when needed boolean newlyCreated = false; if(null == pair) { try { Object obj = _factory.makeObject(); pair = new ObjectTimestampPair(obj); newlyCreated = true; } finally { if (!newlyCreated) { // object cannot be created synchronized (this) { pool.decrementActiveCount(); } } } } // Activate. If activate fails, decrement active count and destroy. // If instance failing activation is new, throw NoSuchElementException; // otherwise keep looping try { _factory.activateObject(key, pair.value); } catch (Exception e) { try { _factory.destroyObject(key,pair.value); synchronized (this) { pool.decrementActiveCount(); } } catch (Exception e2) { // swallowed } if(newlyCreated) { throw new NoSuchElementException( "Could not create a validated object, cause: " + e.getMessage()); } else { continue; // keep looping } } // Validate. If validation fails, decrement active count and // destroy. If instance failing validation is new, throw // NoSuchElementException; otherwise keep looping boolean invalid = true; try { invalid = _testOnBorrow && !_factory.validateObject(key, pair.value); } catch (Exception e) { // swallowed } if (invalid) { try { _factory.destroyObject(key,pair.value); synchronized (this) { pool.decrementActiveCount(); } } catch (Exception e) { // swallowed } if(newlyCreated) { throw new NoSuchElementException("Could not create a validated object"); } // else keep looping } else { return pair.value; } } }