You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by le...@apache.org on 2002/02/12 07:15:26 UTC
cvs commit: jakarta-avalon-excalibur/src/java/org/apache/avalon/excalibur/testcase LatchedThreadGroup.java
leif 02/02/11 22:15:26
Added: src/java/org/apache/avalon/excalibur/testcase
LatchedThreadGroup.java
Log:
Add class to make it easier to write multithreaded tests.
Revision Changes Path
1.1 jakarta-avalon-excalibur/src/java/org/apache/avalon/excalibur/testcase/LatchedThreadGroup.java
Index: LatchedThreadGroup.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.txt file.
*/
package org.apache.avalon.excalibur.testcase;
import junit.framework.TestCase;
import org.apache.avalon.excalibur.testcase.CascadingAssertionFailedError;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
/**
* This class is useful for writing MultiThreaded test cases where you need to perform
* multithreaded load testing on a component.
* <p>
* An instance of will create a block of threads of the specified size. Each thread will be
* assigned to run a specified Runnable instance. The threads will then all wait at a latch
* until the go method is called. The go method will not return until all of the
* Runnables have completed.
*
* @author <a href="mailto:leif@silveregg.co.jp">Leif Mortenson</a>
* @version $Id: LatchedThreadGroup.java,v 1.1 2002/02/12 06:15:26 leif Exp $
*/
public class LatchedThreadGroup
extends AbstractLogEnabled
{
private Thread[] m_threads;
private Object m_semaphore = new Object();
private int m_startedCount;
private boolean m_latched;
private int m_completedCount;
private int m_getCount;
private Throwable m_exception;
/*---------------------------------------------------------------
* Constructors
*-------------------------------------------------------------*/
/**
* Creates a LatchedThreadGroup with a thread for each Runnable in the runnables array.
*/
public LatchedThreadGroup(Runnable[] runnables)
{
int threadCount = runnables.length;
m_threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
m_threads[i] = new Runner( runnables[i], "Latched_Thread_" + i );
}
}
/**
* Creates a LatchedThreadGroup with threadCount threads each running runnable.
*/
public LatchedThreadGroup( Runnable runnable, int threadCount )
{
m_threads = new Thread[threadCount];
for (int i = 0; i < threadCount; i++)
{
m_threads[i] = new Runner( runnable, "Latched_Thread_" + i );
}
}
/*---------------------------------------------------------------
* Methods
*-------------------------------------------------------------*/
protected void resetMemory()
{
System.gc();
System.gc();
// Let the system settle down.
try
{
Thread.sleep( 50 );
}
catch (InterruptedException e ) {}
Runtime runtime = Runtime.getRuntime();
getLogger().debug( "Memory: " + ( runtime.totalMemory() - runtime.freeMemory() ) );
}
/**
* Causes all of the Runnables to start at the same instance. This method will return
* once all of the Runnables have completed.
*
* @returns time, in milliseconds, that it took for all of the Runnables to complete.
*/
public long go()
throws Exception
{
// Start each of the threads. They will block until the latch is released. This is
// necessary because it takes some time for the threads to each allocate their required
// system resources and actually be ready to run.
int threadCount = m_threads.length;
for (int i = 0; i < threadCount; i++)
{
m_threads[i].start();
}
// Wait for all of the threads to start before starting to time the test
synchronized(m_semaphore)
{
while ( m_startedCount < threadCount ) {
m_semaphore.wait();
}
// Start clean
resetMemory();
// Release the threads.
m_latched = true;
getLogger().debug( "Main thread released the test thread latch." );
m_semaphore.notifyAll();
}
// Start timing
long startTime = System.currentTimeMillis();
// Wait for all of the threads to complete
synchronized(m_semaphore)
{
getLogger().debug( "Waiting for test threads to all complete." );
while ( m_completedCount < threadCount ) {
try
{
m_semaphore.wait();
}
catch ( InterruptedException e ) {}
}
}
final long duration = System.currentTimeMillis() - startTime;
getLogger().debug( "All test threads completed." );
if ( m_exception != null )
{
throw new CascadingAssertionFailedError( "Exception in test thread.", m_exception );
}
return duration;
}
/*---------------------------------------------------------------
* Inner Classes
*-------------------------------------------------------------*/
private class Runner extends Thread
{
private Runnable m_runnable;
protected Runner( Runnable runnable, String name )
{
super( name );
m_runnable = runnable;
}
public void run()
{
try
{
// Need all threads to wait until all the others are ready.
synchronized(m_semaphore)
{
m_startedCount++;
getLogger().debug( "Started " + m_startedCount + " test threads." );
if ( m_startedCount >= m_threads.length )
{
m_semaphore.notifyAll();
}
while ( !m_latched )
{
try
{
m_semaphore.wait();
}
catch ( InterruptedException e ) {}
}
}
// Run the runnable
try
{
m_runnable.run();
}
catch (Throwable t)
{
synchronized(m_semaphore)
{
getLogger().error( "Error in " + Thread.currentThread().getName(), t );
if ( m_exception != null )
{
m_exception = t;
}
}
}
}
finally
{
// Say that we are done
synchronized(m_semaphore)
{
m_completedCount++;
getLogger().debug( m_completedCount + " test threads completed." );
m_semaphore.notifyAll();
}
}
}
}
}
--
To unsubscribe, e-mail: <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>