KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > excalibur > thread > impl > WorkerThread


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

17 package org.apache.excalibur.thread.impl;
18
19 import org.apache.excalibur.thread.Executable;
20 import org.apache.excalibur.thread.ThreadControl;
21
22 /**
23  * This class extends the Thread class to add recyclable functionalities.
24  *
25  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
26  */

27 public class WorkerThread
28     extends Thread JavaDoc
29 {
30     /**
31      * Enables debug output of major events. Subclasses which implement
32      * their own logging do not require this to be true.
33      */

34     private static final boolean ENABLE_DEBUG = false;
35     
36     /**
37      * Enables debug output of minor events. Subclasses which implement
38      * their own logging do not require this to be true.
39      */

40     private static final boolean ENABLE_DETAIL_DEBUG = false;
41     
42     /**
43      * The work currentlyy associated with worker (May be null).
44      */

45     private Executable m_work;
46
47     /**
48      * The thread control associated with current work.
49      * Should be null if work is null.
50      */

51     private DefaultThreadControl m_threadControl;
52
53     /**
54      * True if this thread is alive and not scheduled for shutdown.
55      */

56     private boolean m_alive;
57     
58     /**
59      * True if this thread needs to clear the interrupt flag
60      */

61     private boolean m_clearInterruptFlag;
62
63     /**
64      * The thread pool this thread is associated with.
65      */

66     private final AbstractThreadPool m_pool;
67
68     /**
69      * Allocates a new <code>Worker</code> object.
70      */

71     protected WorkerThread( final AbstractThreadPool pool,
72                             final ThreadGroup JavaDoc group,
73                             final String JavaDoc name )
74     {
75         super( group, "" );
76         if( null == name )
77         {
78             throw new NullPointerException JavaDoc( "name" );
79         }
80         if( null == pool )
81         {
82             throw new NullPointerException JavaDoc( "pool" );
83         }
84
85         setName( name );
86         m_work = null;
87         m_alive = true;
88         m_clearInterruptFlag = false;
89         m_pool = pool;
90
91         setDaemon( false );
92     }
93     
94     /**
95      * The main execution loop.
96      */

97     public final synchronized void run()
98     {
99         debug( "starting." );
100         try
101         {
102             while( m_alive )
103             {
104                 waitForWork();
105                 if ( m_alive )
106                 {
107                     detailDebug( "start with work: " + m_work );
108                     
109                     try
110                     {
111                         try
112                         {
113                             preExecute();
114                             
115                             // Actually do the work.
116
m_work.execute();
117                             
118                             // Completed without error, so notify the thread control
119
m_threadControl.finish( null );
120                         }
121                         catch( final ThreadDeath JavaDoc threadDeath )
122                         {
123                             debug( "thread has died." );
124                             m_threadControl.finish( threadDeath );
125                             
126                             // This is to let the thread death propagate to the runtime
127
// enviroment to let it know it must kill this worker
128
throw threadDeath;
129                         }
130                         catch( final Throwable JavaDoc throwable )
131                         {
132                             // Error thrown while working.
133
debug( "error caught", throwable );
134                             m_threadControl.finish( throwable );
135                         }
136                     }
137                     finally
138                     {
139                         detailDebug( "done with work: " + m_work );
140                         
141                         m_work = null;
142                         m_threadControl = null;
143                         
144                         if ( m_clearInterruptFlag )
145                         {
146                             clearInterruptFlag();
147                         }
148                         
149                         postExecute();
150                     }
151                     
152                     /*
153                     try
154                     {
155                         preExecute();
156                         m_work.execute();
157                         if (m_clearInterruptFlag) clearInterruptFlag();
158                         m_threadControl.finish( null );
159                     }
160                     catch( final ThreadDeath threadDeath )
161                     {
162                         debug( "thread has died." );
163                         m_threadControl.finish( threadDeath );
164                         // This is to let the thread death propagate to the runtime
165                         // enviroment to let it know it must kill this worker
166                         throw threadDeath;
167                     }
168                     catch( final Throwable throwable )
169                     {
170                         // Error thrown while working.
171                         debug( "error caught", throwable );
172                         m_threadControl.finish( throwable );
173                     }
174                     finally
175                     {
176                         detailDebug( "done." );
177                         m_work = null;
178                         m_threadControl = null;
179                         if (m_clearInterruptFlag) clearInterruptFlag();
180                         postExecute();
181                     }
182                     */

183         
184                     //should this be just notify or notifyAll ???
185
//It seems to resource intensive option to use notify()
186
//notifyAll();
187

188                     // Let the thread, if any, waiting for the work to complete
189
// know we are done. Should never me more than one thread
190
// waiting, so notifyAll is not necessary.
191
notify();
192         
193                     // recycle ourselves
194
recycleThread();
195                 }
196             }
197         }
198         finally
199         {
200             debug( "stopped." );
201         }
202     }
203
204     /**
205      * Implement this method to replace thread back into pool.
206      */

207     protected void recycleThread()
208     {
209         if ( !m_alive )
210         {
211             throw new IllegalStateException JavaDoc( "Attempted to recycle dead thread." );
212         }
213         
214         detailDebug( "recycle." );
215         if ( m_clearInterruptFlag )
216         {
217             clearInterruptFlag();
218         }
219         m_pool.releaseWorker( this );
220     }
221
222     /**
223      * Overide this method to execute something after
224      * each bit of "work".
225      */

226     protected void postExecute()
227     {
228     }
229
230     /**
231      * Overide this method to execute something before
232      * each bit of "work".
233      */

234     protected void preExecute()
235     {
236         clearInterruptFlag();
237         //TODO: Thread name setting should reuse the
238
//ThreadContext code if ThreadContext used.
239
}
240
241     /**
242      * Clears the interrupt flag for this thread. Since Java does
243      * not provide a method that does this for an external thread,
244      * we have to verify that we are in the WorkerThread. If the
245      * code calling this method does not originate from this thread,
246      * we set a flag and wait for it to be called internally.
247      */

248     public void clearInterruptFlag()
249     {
250         if (Thread.currentThread().equals(this))
251         {
252             Thread.interrupted();
253             m_clearInterruptFlag = false;
254         }
255         else
256         {
257             m_clearInterruptFlag = true;
258         }
259     }
260
261     /**
262      * Set the <tt>alive</tt> variable to false causing the worker to die.
263      * If the worker is stalled and a timeout generated this call, this method
264      * does not change the state of the worker (that must be destroyed in other
265      * ways).
266      * <p>
267      * This is called by the pool when it is removed.
268      */

269     public void dispose()
270     {
271         debug( "destroying." );
272         
273         m_alive = false;
274         
275         // Notify the thread so it will be woken up and notice that it has been destroyed.
276
synchronized(this)
277         {
278             this.notify();
279         }
280         
281         debug( "destroyed." );
282     }
283
284     /**
285      * Set the <tt>Work</tt> code this <tt>Worker</tt> must
286      * execute and <i>notifies</i> its thread to do it.
287      */

288     protected synchronized ThreadControl execute( final Executable work )
289     {
290         m_work = work;
291         m_threadControl = new DefaultThreadControl( this );
292
293         detailDebug( "notifying this worker of new work: " + work.toString() );
294         notify();
295
296         return m_threadControl;
297     }
298
299     /**
300      * Set the <tt>Work</tt> code this <tt>Worker</tt> must
301      * execute and <i>notifies</i> its thread to do it. Wait
302      * until the executable has finished before returning.
303      */

304     protected void executeAndWait( final Executable work )
305     {
306         // Assign work to the thread.
307
execute( work );
308         
309         // Wait for the work to complete.
310
synchronized(this)
311         {
312             while( null != m_work )
313             {
314                 try
315                 {
316                     detailDebug( "waiting for work to complete." );
317                     wait();
318                     detailDebug( "notified." );
319                 }
320                 catch( final InterruptedException JavaDoc ie )
321                 {
322                     // Ignore
323
}
324             }
325         }
326     }
327     
328     /**
329      * For for new work to arrive or for the thread to be destroyed.
330      */

331     private void waitForWork()
332     {
333         synchronized(this)
334         {
335             while( m_alive && ( null == m_work ) )
336             {
337                 try
338                 {
339                     detailDebug( "waiting for work." );
340                     wait();
341                     detailDebug( "notified." );
342                 }
343                 catch( final InterruptedException JavaDoc ie )
344                 {
345                     // Ignore
346
}
347             }
348         }
349     }
350
351     /**
352      * Used to log major events against the worker. Creation, deletion,
353      * uncaught exceptions etc.
354      * <p>
355      * This implementation is a Noop. Subclasses can override to actually
356      * do some logging.
357      *
358      * @param message Message to log.
359      */

360     protected void debug( final String JavaDoc message )
361     {
362         if( ENABLE_DEBUG )
363         {
364             System.out.println( getName() + ": " + message );
365         }
366     }
367     
368     /**
369      * Used to log major events against the worker. Creation, deletion,
370      * uncaught exceptions etc.
371      * <p>
372      * This implementation is a Noop. Subclasses can override to actually
373      * do some logging.
374      *
375      * @param message Message to log.
376      * @param throwable Throwable to log with the message.
377      */

378     protected void debug( final String JavaDoc message, final Throwable JavaDoc throwable )
379     {
380         if( ENABLE_DEBUG )
381         {
382             System.out.println( getName() + ": " + message + ": " + throwable );
383         }
384     }
385     
386     /**
387      * Used to log minor events against the worker. Start and stop of
388      * individual pieces of work etc. Separated from the major events
389      * so that they are not lost in a sea of minor events.
390      * <p>
391      * This implementation is a Noop. Subclasses can override to actually
392      * do some logging.
393      *
394      * @param message Message to log.
395      */

396     protected void detailDebug( final String JavaDoc message )
397     {
398         if ( ENABLE_DETAIL_DEBUG )
399         {
400             System.out.println( getName() + ": " + message );
401         }
402     }
403     
404     /**
405      * Used to log minor events against the worker. Start and stop of
406      * individual pieces of work etc. Separated from the major events
407      * so that they are not lost in a sea of minor events.
408      * <p>
409      * This implementation is a Noop. Subclasses can override to actually
410      * do some logging.
411      *
412      * @param message Message to log.
413      * @param throwable Throwable to log with the message.
414      */

415     protected void detailDebug( final String JavaDoc message, final Throwable JavaDoc throwable )
416     {
417         if ( ENABLE_DETAIL_DEBUG )
418         {
419             System.out.println( getName() + ": " + message + ": " + throwable );
420         }
421     }
422 }
423
Popular Tags