KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > excalibur > pool > test > LatchedThreadGroup


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
14  * implied.
15  *
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */

19 package org.apache.avalon.excalibur.pool.test;
20
21 import org.apache.avalon.framework.logger.AbstractLogEnabled;
22 import org.apache.avalon.framework.logger.Logger;
23
24 /**
25  * This class is useful for writing MultiThreaded test cases where you need to perform
26  * multithreaded load testing on a component.
27  * <p>
28  * An instance of will create a block of threads of the specified size. Each thread will be
29  * assigned to run a specified Runnable instance. The threads will then all wait at a latch
30  * until the go method is called. The go method will not return until all of the
31  * Runnables have completed.
32  *
33  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
34  * @version $Id: LatchedThreadGroup.java,v 1.2 2004/03/29 16:50:37 mcconnell Exp $
35  */

36 public class LatchedThreadGroup
37     extends AbstractLogEnabled
38 {
39     private Thread JavaDoc[] m_threads;
40     private Object JavaDoc m_semaphore = new Object JavaDoc();
41     private int m_startedCount;
42     private boolean m_latched;
43     private int m_completedCount;
44     private Throwable JavaDoc m_exception;
45
46     /*---------------------------------------------------------------
47      * Constructors
48      *-------------------------------------------------------------*/

49     /**
50      * Creates a LatchedThreadGroup with a thread for each Runnable in the runnables array.
51      */

52     public LatchedThreadGroup( Runnable JavaDoc[] runnables )
53     {
54         int threadCount = runnables.length;
55         m_threads = new Thread JavaDoc[ threadCount ];
56         for( int i = 0; i < threadCount; i++ )
57         {
58             m_threads[ i ] = new Runner( runnables[ i ], "Latched_Thread_" + i );
59         }
60     }
61
62     /**
63      * Creates a LatchedThreadGroup with threadCount threads each running runnable.
64      */

65     public LatchedThreadGroup( Runnable JavaDoc runnable, int threadCount )
66     {
67         m_threads = new Thread JavaDoc[ threadCount ];
68         for( int i = 0; i < threadCount; i++ )
69         {
70             m_threads[ i ] = new Runner( runnable, "Latched_Thread_" + i );
71         }
72     }
73
74     /*---------------------------------------------------------------
75      * Methods
76      *-------------------------------------------------------------*/

77     protected void resetMemory()
78     {
79         System.gc();
80         System.gc();
81
82         // Let the system settle down.
83
try
84         {
85             Thread.sleep( 50 );
86         }
87         catch( InterruptedException JavaDoc e )
88         {
89         }
90         Runtime JavaDoc runtime = Runtime.getRuntime();
91         getLogger().debug( "Memory: " + ( runtime.totalMemory() - runtime.freeMemory() ) );
92     }
93
94     /**
95      * Causes all of the Runnables to start at the same instance. This method will return
96      * once all of the Runnables have completed.
97      *
98      * @return time, in milliseconds, that it took for all of the Runnables to complete.
99      */

100     public long go()
101         throws Exception JavaDoc
102     {
103         // Start each of the threads. They will block until the latch is released. This is
104
// necessary because it takes some time for the threads to each allocate their required
105
// system resources and actually be ready to run.
106
int threadCount = m_threads.length;
107         for( int i = 0; i < threadCount; i++ )
108         {
109             m_threads[ i ].start();
110         }
111
112         // Wait for all of the threads to start before starting to time the test
113
synchronized( m_semaphore )
114         {
115             while( m_startedCount < threadCount )
116             {
117                 m_semaphore.wait();
118             }
119
120             // Start clean
121
resetMemory();
122
123             // Release the threads.
124
m_latched = true;
125             getLogger().debug( "Main thread released the test thread latch." );
126             m_semaphore.notifyAll();
127         }
128         // Start timing
129
long startTime = System.currentTimeMillis();
130
131         // Wait for all of the threads to complete
132
synchronized( m_semaphore )
133         {
134             getLogger().debug( "Waiting for test threads to all complete." );
135             while( m_completedCount < threadCount )
136             {
137                 try
138                 {
139                     m_semaphore.wait();
140                 }
141                 catch( InterruptedException JavaDoc e )
142                 {
143                 }
144             }
145         }
146         final long duration = System.currentTimeMillis() - startTime;
147         getLogger().debug( "All test threads completed." );
148
149         if( m_exception != null )
150         {
151             throw new CascadingAssertionFailedError( "Exception in test thread.", m_exception );
152         }
153         return duration;
154     }
155
156     /**
157      * Inner access method to getLogger() to work around a bug in the Javac compiler
158      * when getLogger() is called from the method of an inner class. Jikes seems to
159      * handle it Ok. :-/
160      */

161     private Logger getInnerLogger()
162     {
163         return getLogger();
164     }
165
166     /*---------------------------------------------------------------
167      * Inner Classes
168      *-------------------------------------------------------------*/

169     private class Runner extends Thread JavaDoc
170     {
171         private Runnable JavaDoc m_runnable;
172
173         protected Runner( Runnable JavaDoc runnable, String JavaDoc name )
174         {
175             super( name );
176             m_runnable = runnable;
177         }
178
179         public void run()
180         {
181             try
182             {
183                 // Need all threads to wait until all the others are ready.
184
synchronized( m_semaphore )
185                 {
186                     m_startedCount++;
187                     getInnerLogger().debug( "Started " + m_startedCount + " test threads." );
188                     if( m_startedCount >= m_threads.length )
189                     {
190                         m_semaphore.notifyAll();
191                     }
192                     while( !m_latched )
193                     {
194                         try
195                         {
196                             m_semaphore.wait();
197                         }
198                         catch( InterruptedException JavaDoc e )
199                         {
200                         }
201                     }
202                 }
203
204                 // Run the runnable
205
try
206                 {
207                     m_runnable.run();
208                 }
209                 catch( Throwable JavaDoc t )
210                 {
211                     synchronized( m_semaphore )
212                     {
213                         getInnerLogger().error( "Error in " + Thread.currentThread().getName(), t );
214                         if( m_exception != null )
215                         {
216                             m_exception = t;
217                         }
218                     }
219                 }
220             }
221             finally
222             {
223                 // Say that we are done
224
synchronized( m_semaphore )
225                 {
226                     m_completedCount++;
227                     getInnerLogger().debug( m_completedCount + " test threads completed." );
228                     m_semaphore.notifyAll();
229                 }
230             }
231         }
232     }
233 }
234
Popular Tags