You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@avalon.apache.org by bl...@apache.org on 2001/03/01 21:11:04 UTC
cvs commit: jakarta-avalon/src/java/org/apache/avalon/util/thread ThreadPool.java
bloritsch 01/03/01 12:11:03
Modified: src/java/org/apache/avalon/util/datasource
JdbcConnectionPool.java
src/java/org/apache/avalon/util/pool AbstractPool.java
DefaultObjectFactory.java DefaultPool.java
ObjectFactory.java ThreadSafePool.java
src/java/org/apache/avalon/util/thread ThreadPool.java
Added: src/java/org/apache/avalon/util/pool Resizable.java
SingleThreadedPool.java
Log:
Beefed up the AbstractPool and ThreadsafePool.
Both should be robust for multithreaded environments.
Revision Changes Path
1.2 +10 -6 jakarta-avalon/src/java/org/apache/avalon/util/datasource/JdbcConnectionPool.java
Index: JdbcConnectionPool.java
===================================================================
RCS file: /home/cvs/jakarta-avalon/src/java/org/apache/avalon/util/datasource/JdbcConnectionPool.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- JdbcConnectionPool.java 2001/02/24 03:59:38 1.1
+++ JdbcConnectionPool.java 2001/03/01 20:10:47 1.2
@@ -24,7 +24,7 @@
* thread to manage the number of SQL Connections.
*
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
- * @version CVS $Revision: 1.1 $ $Date: 2001/02/24 03:59:38 $
+ * @version CVS $Revision: 1.2 $ $Date: 2001/03/01 20:10:47 $
*/
public class JdbcConnectionPool
extends AbstractLoggable
@@ -145,9 +145,13 @@
}
else
{
- synchronized( m_active )
+ synchronized( m_ready )
{
obj = (Poolable)m_ready.remove( 0 );
+ }
+
+ synchronized( m_active )
+ {
m_active.add( obj );
}
}
@@ -180,7 +184,7 @@
if( m_ready.size() < m_min )
{
getLogger().debug( "There are not enough Connections for pool: " + m_dburl );
-
+
while( ( m_ready.size() < m_min ) && ( m_currentCount < m_max ) )
{
m_ready.add( createJdbcConnection() );
@@ -190,17 +194,17 @@
{
getLogger().debug( "Trimming excess fat from pool: " + m_dburl );
- while( m_ready.size() > m_min )
+ while( m_ready.size() > m_min )
{
recycle( (Recyclable)m_ready.remove( 0 ) );
- }
+ }
}
}
try
{
Thread.sleep( 1 * 60 * 1000 );
- }
+ }
catch( final InterruptedException ie )
{
getLogger().warn( "Caught an InterruptedException", ie );
1.2 +101 -106 jakarta-avalon/src/java/org/apache/avalon/util/pool/AbstractPool.java
Index: AbstractPool.java
===================================================================
RCS file: /home/cvs/jakarta-avalon/src/java/org/apache/avalon/util/pool/AbstractPool.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- AbstractPool.java 2001/02/24 03:59:41 1.1
+++ AbstractPool.java 2001/03/01 20:10:51 1.2
@@ -7,153 +7,148 @@
*/
package org.apache.avalon.util.pool;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.avalon.AbstractLoggable;
+import org.apache.avalon.Initializable;
import org.apache.avalon.Poolable;
import org.apache.avalon.Recyclable;
-import org.apache.avalon.Initializable;
/**
* This is an <code>Pool</code> that caches Poolable objects for reuse.
*
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
- * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
- * @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
-public class AbstractPool
- implements Pool, Initializable
-{
- protected int m_count;
- protected Poolable[] m_pool;
- protected ObjectFactory m_factory;
- protected PoolController m_controller;
- protected int m_maximum;
- protected int m_initial;
+public class AbstractPool extends AbstractLoggable implements Pool {
+ protected final ObjectFactory m_factory;
+ protected final PoolController m_controller;
+ protected final int m_min;
+ protected int m_max;
+ protected int m_currentCount = 0;
+ protected List m_active = new ArrayList();
+ protected List m_ready = new ArrayList();
+
+ /**
+ * Create an AbstractPool. The pool requires a factory, and can
+ * optionally have a controller.
+ */
public AbstractPool( final ObjectFactory factory,
final PoolController controller,
- final int initial,
- final int maximum )
+ final int min,
+ final int max ) throws Exception
{
- m_count = 0;
m_factory = factory;
m_controller = controller;
- m_maximum = maximum;
- m_initial = initial;
- }
-
- public void init()
- throws Exception
- {
- grow( m_maximum );
- fill( m_initial );
- }
+ int t_max = max;
+ int t_min = min;
- /**
- * Retrieve an object from pool.
- *
- * @return an object from Pool
- */
- public Poolable get() throws Exception
- {
- if( null == m_pool && null != m_controller )
+ if( min < 0 )
{
- final int increase = m_controller.grow();
- if( increase > 0 ) grow( increase );
- }
+ if (getLogger() != null)
+ getLogger().warn( "Minumum number of connections specified is " +
+ "less than 0, using 0" );
- if( 0 == m_count )
+ t_min = 0;
+ }
+ else
{
- return m_factory.newInstance();
+ t_min = min;
}
-
- m_count--;
-
- final Poolable poolable = m_pool[ m_count ];
- m_pool[ m_count ] = null;
- return poolable;
- }
- /**
- * Place an object in pool.
- *
- * @param poolable the object to be placed in pool
- */
- public void put( final Poolable poolable )
- {
- if( poolable instanceof Recyclable )
+ if( ( max < min ) || ( max < 1 ) )
{
- ((Recyclable)poolable).recycle();
+ if (getLogger() != null)
+ getLogger().warn( "Maximum number of connections specified must be at " +
+ "least 1 and must be greater than the minumum number " +
+ "of connections" );
+ t_max = ( min > 1 ) ? min : 1;
}
-
- if( m_pool.length == (m_count + 1) && null != m_controller )
+ else
{
- final int decrease = m_controller.shrink();
- if( decrease > 0 ) shrink( decrease );
+ t_max = max;
}
- if ( m_pool.length > m_count + 1 )
- {
- m_pool[ m_count++ ] = poolable;
+ m_max = t_max;
+ m_min = t_min;
+
+ if (! (this instanceof Initializable)) {
+ init();
}
}
- /**
- * Return the total number of slots in Pool
- *
- * @return the total number of slots
- */
- public final int getCapacity()
+ protected void init() throws Exception
{
- return m_pool.length;
+ for( int i = 0; i < m_min; i++ )
+ {
+ m_ready.add( m_factory.newInstance() );
+ m_currentCount++;
+ }
}
- /**
- * Get the number of used slots in Pool
- *
- * @return the number of used slots
- */
- public final int getSize()
+ public synchronized Poolable get()
+ throws Exception
{
- return m_count;
- }
+ Poolable obj = null;
- /**
- * This fills the pool to the size specified in parameter.
- */
- public final void fill( final int fillSize ) throws Exception
- {
- final int size = Math.min( m_pool.length, fillSize );
+ if( 0 == m_ready.size() )
+ {
+ if( m_currentCount < m_max )
+ {
+ int amount = (m_controller == null) ? 1 : m_controller.grow();
+ obj = m_factory.newInstance();
+ m_active.add( obj );
+ m_currentCount++;
+ amount--;
- for( int i = m_count; i < size; i++ )
+ while ((amount > 0) && (m_currentCount < m_max)) {
+ m_ready.add( m_factory.newInstance() );
+ m_currentCount++;
+ amount--;
+ notify();
+ }
+ }
+ else
+ {
+ if (this instanceof Resizable) {
+ int amount = (m_controller == null) ? 1 : m_controller.grow();
+ ((Resizable) this).grow(amount);
+ return get();
+ } else {
+ throw new Exception( m_factory.getCreatedClass().getName() + ": not available" );
+ }
+ }
+ }
+ else
{
- m_pool[i] = m_factory.newInstance();
+ obj = (Poolable)m_ready.remove( 0 );
+ m_active.add( obj );
}
+
+ if (getLogger() != null)
+ getLogger().debug( m_factory.getCreatedClass().getName() + ": requested from the pool." );
- m_count = size;
+ return obj;
}
- /**
- * This fills the pool by the size specified in parameter.
- */
- public final void grow( final int increase )
+ public synchronized void put( final Poolable obj )
{
- if( null == m_pool )
+ if (! m_active.remove( obj ))
{
- m_pool = new Poolable[ increase ];
- return;
+ try {
+ m_factory.decommission( obj );
+ } catch (Exception e) {
+ if (getLogger() != null)
+ getLogger().warn( m_factory.getCreatedClass().getName() + ": error decommissioning object.", e );
+ }
}
-
- final Poolable[] poolables = new Poolable[ increase + m_pool.length ];
- System.arraycopy( m_pool, 0, poolables, 0, m_pool.length );
- m_pool = poolables;
- }
+ else
+ {
+ m_ready.add( obj );
+ }
- /**
- * This shrinks the pool by parameter size.
- */
- public final void shrink( final int decrease )
- {
- final Poolable[] poolables = new Poolable[ m_pool.length - decrease ];
- System.arraycopy( m_pool, 0, poolables, 0, poolables.length );
- m_pool = poolables;
+ if (getLogger() != null)
+ getLogger().debug( m_factory.getCreatedClass().getName() + ": returned to the pool." );
}
-}
+}
\ No newline at end of file
1.2 +10 -5 jakarta-avalon/src/java/org/apache/avalon/util/pool/DefaultObjectFactory.java
Index: DefaultObjectFactory.java
===================================================================
RCS file: /home/cvs/jakarta-avalon/src/java/org/apache/avalon/util/pool/DefaultObjectFactory.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DefaultObjectFactory.java 2001/02/24 03:59:41 1.1
+++ DefaultObjectFactory.java 2001/03/01 20:10:51 1.2
@@ -32,8 +32,8 @@
m_constructor = constructor;
}
- public DefaultObjectFactory( final Class clazz,
- final Class[] arguementClasses,
+ public DefaultObjectFactory( final Class clazz,
+ final Class[] arguementClasses,
final Object[] arguements )
throws NoSuchMethodException
{
@@ -56,11 +56,16 @@
try
{
return (Poolable)m_constructor.newInstance( m_arguements );
- }
- catch( final Exception e )
+ }
+ catch( final Exception e )
{
- throw new Error( "Failed to instantiate the class " +
+ throw new Error( "Failed to instantiate the class " +
m_constructor.getDeclaringClass().getName() + " due to " + e );
}
+ }
+
+ public void decommission(Poolable object)
+ {
+ object = null;
}
}
1.2 +6 -6 jakarta-avalon/src/java/org/apache/avalon/util/pool/DefaultPool.java
Index: DefaultPool.java
===================================================================
RCS file: /home/cvs/jakarta-avalon/src/java/org/apache/avalon/util/pool/DefaultPool.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- DefaultPool.java 2001/02/24 03:59:41 1.1
+++ DefaultPool.java 2001/03/01 20:10:52 1.2
@@ -18,30 +18,30 @@
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class DefaultPool
- extends AbstractPool
+ extends SingleThreadedPool
{
public final static int DEFAULT_POOL_SIZE = 8;
- public DefaultPool( final ObjectFactory factory,
- final PoolController controller )
+ public DefaultPool( final ObjectFactory factory,
+ final PoolController controller )
throws Exception
{
super( factory, controller, DEFAULT_POOL_SIZE, DEFAULT_POOL_SIZE );
}
- public DefaultPool( final ObjectFactory factory )
+ public DefaultPool( final ObjectFactory factory )
throws Exception
{
this( factory, null );
}
- public DefaultPool( final Class clazz, final int initial, final int maximum )
+ public DefaultPool( final Class clazz, final int initial, final int maximum )
throws NoSuchMethodException, Exception
{
super( new DefaultObjectFactory( clazz ), null, initial, maximum );
}
- public DefaultPool( final Class clazz, final int initial )
+ public DefaultPool( final Class clazz, final int initial )
throws NoSuchMethodException, Exception
{
this( clazz, initial, initial );
1.2 +2 -1 jakarta-avalon/src/java/org/apache/avalon/util/pool/ObjectFactory.java
Index: ObjectFactory.java
===================================================================
RCS file: /home/cvs/jakarta-avalon/src/java/org/apache/avalon/util/pool/ObjectFactory.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ObjectFactory.java 2001/02/24 03:59:41 1.1
+++ ObjectFactory.java 2001/03/01 20:10:53 1.2
@@ -17,9 +17,10 @@
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
-public interface ObjectFactory
+public interface ObjectFactory
extends Component
{
Poolable newInstance() throws Exception;
Class getCreatedClass();
+ void decommission(Poolable object) throws Exception;
}
1.2 +25 -63 jakarta-avalon/src/java/org/apache/avalon/util/pool/ThreadSafePool.java
Index: ThreadSafePool.java
===================================================================
RCS file: /home/cvs/jakarta-avalon/src/java/org/apache/avalon/util/pool/ThreadSafePool.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ThreadSafePool.java 2001/02/24 03:59:41 1.1
+++ ThreadSafePool.java 2001/03/01 20:10:53 1.2
@@ -7,6 +7,7 @@
*/
package org.apache.avalon.util.pool;
+import org.apache.avalon.Initializable;
import org.apache.avalon.Poolable;
import org.apache.avalon.Recyclable;
import org.apache.avalon.ThreadSafe;
@@ -20,102 +21,69 @@
*/
public class ThreadSafePool
extends AbstractPool
- implements ThreadSafe
+ implements ThreadSafe, Initializable
{
public final static int DEFAULT_POOL_SIZE = 8;
- protected boolean m_blocking = false;
-
public ThreadSafePool( final ObjectFactory factory, final PoolController controller )
- throws Exception
+ throws Exception
{
super( factory, controller, DEFAULT_POOL_SIZE, DEFAULT_POOL_SIZE );
}
public ThreadSafePool( final ObjectFactory factory )
- throws Exception
+ throws Exception
{
this( factory, null );
}
- public ThreadSafePool( final ObjectFactory factory,
- final int initial,
+ public ThreadSafePool( final ObjectFactory factory,
+ final int initial,
final int maximum )
- throws Exception
+ throws Exception
{
super( factory, null, initial, maximum );
}
public ThreadSafePool( final ObjectFactory factory, final int initial )
- throws Exception
+ throws Exception
{
this( factory, initial, initial );
}
- public ThreadSafePool( final Class clazz, final int initial, final int maximum )
+ public ThreadSafePool( final Class clazz, final int initial, final int maximum )
throws NoSuchMethodException, Exception
{
this( new DefaultObjectFactory( clazz ), initial, maximum );
}
- public ThreadSafePool( final Class clazz, final int initial )
+ public ThreadSafePool( final Class clazz, final int initial )
throws NoSuchMethodException, Exception
{
this( clazz, initial, initial );
}
-
- public final boolean isBlocking()
- {
- return m_blocking;
- }
- /**
- * Set whether this pool is blocking.
- *
- * If this pool is blocking and empties the Pool then the thread will block until
- * an object is placed back in the pool. This has to be used with care as an errant
- * thread who never does a put will force blocked clients to wait forever.
- *
- * @param blocking a boolean indicating if it is blocking or not
- */
- public final void setBlocking( final boolean blocking )
- {
- m_blocking = blocking;
+ public void init() {
+ try {
+ super.init();
+ } catch (Exception e) {
+ getLogger().debug("Caught init exception", e);
+ }
}
-
/**
* Retrieve an object from pool.
*
* @return an object from Pool
*/
- public final Poolable get() throws Exception
+ public final synchronized Poolable get() throws Exception
{
- //Require this or else the wait later will cause
- final Poolable[] pool = m_pool;
-
- synchronized( pool )
+ while ( this.m_ready.size() == 0 )
{
- if( 0 == m_count )
- {
- if( !m_blocking )
- {
- return m_factory.newInstance();
- }
- else
- {
- while( 0 == m_count )
- {
- try { pool.wait(); }
- catch( final InterruptedException ie ) { }
- }
- }
- }
-
- m_count--;
- final Poolable poolable = m_pool[ m_count ];
- m_pool[ m_count ] = null;
- return poolable;
+ try { wait(); }
+ catch( final InterruptedException ie ) { }
}
+
+ return super.get();
}
/**
@@ -123,16 +91,10 @@
*
* @param poolable the object to be placed in pool
*/
- public final void put( final Poolable poolable )
+ public final synchronized void put( final Poolable poolable )
{
- final Poolable[] pool = m_pool;
+ super.put( poolable );
- synchronized( pool )
- {
- super.put( poolable );
-
- //if someone was waiting on the old pool then we have to notify them
- pool.notifyAll();
- }
+ notify();
}
}
1.1 jakarta-avalon/src/java/org/apache/avalon/util/pool/Resizable.java
Index: Resizable.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.util.pool;
/**
* This is the interface for Pools that are not a fixed size.
*
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
*/
public interface Resizable {
void grow(int amount);
void shrink(int amount);
}
1.1 jakarta-avalon/src/java/org/apache/avalon/util/pool/SingleThreadedPool.java
Index: SingleThreadedPool.java
===================================================================
/*
* Copyright (C) The Apache Software Foundation. All rights reserved.
*
* This software is published under the terms of the Apache Software License
* version 1.1, a copy of which has been included with this distribution in
* the LICENSE file.
*/
package org.apache.avalon.util.pool;
import org.apache.avalon.Poolable;
import org.apache.avalon.Recyclable;
import org.apache.avalon.Initializable;
import org.apache.avalon.SingleThreaded;
/**
* This is an <code>Pool</code> that caches Poolable objects for reuse.
*
* @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
public class SingleThreadedPool
implements Pool, SingleThreaded, Resizable
{
protected int m_count;
protected Poolable[] m_pool;
protected ObjectFactory m_factory;
protected PoolController m_controller;
protected int m_maximum;
protected int m_initial;
public SingleThreadedPool( final ObjectFactory factory,
final PoolController controller,
final int initial,
final int maximum ) throws Exception
{
m_count = 0;
m_factory = factory;
m_controller = controller;
m_maximum = maximum;
m_initial = initial;
if (! (this instanceof Initializable)) {
init();
}
}
public void init()
throws Exception
{
grow( m_maximum );
fill( m_initial );
}
/**
* Retrieve an object from pool.
*
* @return an object from Pool
*/
public Poolable get() throws Exception
{
if( null == m_pool && null != m_controller )
{
final int increase = m_controller.grow();
if( increase > 0 ) grow( increase );
}
if( 0 == m_count )
{
return m_factory.newInstance();
}
m_count--;
final Poolable poolable = m_pool[ m_count ];
m_pool[ m_count ] = null;
return poolable;
}
/**
* Place an object in pool.
*
* @param poolable the object to be placed in pool
*/
public void put( final Poolable poolable )
{
if( poolable instanceof Recyclable )
{
((Recyclable)poolable).recycle();
}
if( m_pool.length == (m_count + 1) && null != m_controller )
{
final int decrease = m_controller.shrink();
if( decrease > 0 ) shrink( decrease );
}
if ( m_pool.length > m_count + 1 )
{
m_pool[ m_count++ ] = poolable;
}
}
/**
* Return the total number of slots in Pool
*
* @return the total number of slots
*/
public final int getCapacity()
{
return m_pool.length;
}
/**
* Get the number of used slots in Pool
*
* @return the number of used slots
*/
public final int getSize()
{
return m_count;
}
/**
* This fills the pool to the size specified in parameter.
*/
public final void fill( final int fillSize ) throws Exception
{
final int size = Math.min( m_pool.length, fillSize );
for( int i = m_count; i < size; i++ )
{
m_pool[i] = m_factory.newInstance();
}
m_count = size;
}
/**
* This fills the pool by the size specified in parameter.
*/
public final void grow( final int increase )
{
if( null == m_pool )
{
m_pool = new Poolable[ increase ];
return;
}
final Poolable[] poolables = new Poolable[ increase + m_pool.length ];
System.arraycopy( m_pool, 0, poolables, 0, m_pool.length );
m_pool = poolables;
}
/**
* This shrinks the pool by parameter size.
*/
public final void shrink( final int decrease )
{
final Poolable[] poolables = new Poolable[ m_pool.length - decrease ];
System.arraycopy( m_pool, 0, poolables, 0, poolables.length );
m_pool = poolables;
}
}
1.2 +15 -10 jakarta-avalon/src/java/org/apache/avalon/util/thread/ThreadPool.java
Index: ThreadPool.java
===================================================================
RCS file: /home/cvs/jakarta-avalon/src/java/org/apache/avalon/util/thread/ThreadPool.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- ThreadPool.java 2001/02/24 03:59:43 1.1
+++ ThreadPool.java 2001/03/01 20:11:01 1.2
@@ -21,7 +21,7 @@
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @author <a href="mailto:donaldp@apache.org">Peter Donald</a>
*/
-public class ThreadPool
+public class ThreadPool
extends ThreadGroup
implements ObjectFactory, Loggable
{
@@ -36,12 +36,11 @@
}
public ThreadPool( final String name, final int capacity )
- throws Exception
+ throws Exception
{
super( name );
m_pool = new ThreadSafePool( this, 0 );
m_pool.init();
- m_pool.grow( capacity );
}
public void setLogger( final Logger logger )
@@ -51,38 +50,44 @@
public Poolable newInstance()
{
- final WorkerThread worker =
+ final WorkerThread worker =
new WorkerThread( this, m_pool, getName() + " Worker #" + m_level++ );
worker.setLogger( m_logger );
worker.start();
return worker;
}
+ public void decommission(Poolable object) {
+ if (object instanceof WorkerThread) {
+ ((WorkerThread) object).dispose();
+ }
+ }
+
public Class getCreatedClass()
{
return WorkerThread.class;
}
-
- public void execute( final Runnable work )
+
+ public void execute( final Runnable work )
throws Exception
{
execute( work, Thread.NORM_PRIORITY );
}
- public void execute( final Runnable work, final int priority )
+ public void execute( final Runnable work, final int priority )
throws Exception
{
final WorkerThread worker = getWorker( priority );
worker.execute( work );
}
-
- public void executeAndWait( final Runnable work )
+
+ public void executeAndWait( final Runnable work )
throws Exception
{
executeAndWait( work, Thread.NORM_PRIORITY );
}
- public void executeAndWait( final Runnable work, final int priority )
+ public void executeAndWait( final Runnable work, final int priority )
throws Exception
{
final WorkerThread worker = getWorker( priority );