View Javadoc

1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.apache.jetspeed.services.threadpool;
18  
19  //turbine stuff
20  import org.apache.turbine.services.TurbineServices;
21  
22  // Jetspeed classes
23  import org.apache.jetspeed.services.logging.JetspeedLogFactoryService;
24  import org.apache.jetspeed.services.logging.JetspeedLogger;
25  
26  /***
27   * A thread that is used to process Runnables.  This thread will wait until it is 
28   * notified by another thread that it needs processing.  However it will only 
29   * process if getRunnable != null.
30   *
31   * @author <a href="mailto:burton@apache.org">Kevin A. Burton</a>
32   * @author <a href="mailto:sgala@apache.org">Santiago Gala</a>
33   * @version $Id: RunnableThread.java,v 1.7 2004/02/23 03:51:31 jford Exp $
34   */
35  public class RunnableThread extends Thread 
36  {
37      /***
38       * Static initialization of the logger for this class
39       */    
40      private static final JetspeedLogger logger = JetspeedLogFactoryService.getLogger(RunnableThread.class.getName());
41      
42      private boolean running = false;
43      private static int next_id = 0;
44  
45      /***
46       * Increment a counter so that we can identify threads
47       * easily.
48       */
49      private static synchronized int getNextId() {
50          return ++next_id;
51      };
52      private int id = 0;
53  
54      /***
55      The runnable that you want to process
56      */
57      private Runnable runnable = null;
58      
59      public RunnableThread()
60      {
61          super();
62          this.setDaemon(true);
63      }
64  
65      /***
66       * Creates a new Thread in the specified threadgroup
67       *
68       * @param tg the Threadgroup which will contain the new Thread
69       */
70      public RunnableThread( ThreadGroup tg) {
71          super( tg, "Provisory");
72          this.id = getNextId();
73          super.setName("RunnableThread:" + this.id );
74          this.setPriority( Thread.MIN_PRIORITY );
75          this.setDaemon(true);
76  
77      }
78  
79      /***
80       * Creates a new Thread in the specified threadgroup and assigns
81       * it an id.
82       *
83       * @param tg the Threadgroup which will contain the new Thread
84       * @param id an identifier for the new Thread
85       */
86      public RunnableThread( ThreadGroup tg, 
87                             int id ) {
88  
89          super( tg, "RunnableThread:" + id );
90          this.setPriority( Thread.MIN_PRIORITY );
91          this.setDaemon(true);       
92          this.id = id;
93      }
94      
95      /***
96       * Processes the Runnable object assigned to it, whenever one
97       * is available
98       */
99      public void run() {
100 
101         /*
102           FIXME: move to a static class variable to allow for pool shutdown
103         */
104         boolean poolrunning  = true;
105         while ( poolrunning ) {
106 
107 
108             //On creation, we are idle.
109             //So, add ourselves to the Pool.
110             //Next times we come here, we are just finished
111             //one run...
112             this.setRunning( false );                
113 
114             this.setRunnable( null );
115                 
116             synchronized( this ) {
117                 if( this.getPriority() != 
118                     JetspeedThreadPoolService.DEFAULT_THREAD_PRIORITY ) {
119                     //give the thread back it's default priority.
120                     this.setPriority( JetspeedThreadPoolService.DEFAULT_THREAD_PRIORITY );
121                 }
122                 
123                 //SGP I don't think it is needed. The scheduler will do its job
124                 //and the thread will be released sooner. Later, it will wait
125                 //until the Pool reuses it. Correct me if I'm wrong
126                 //but please comment the reasons, as I don't get it :)
127 
128                 //yield this thread so that other threads can now execute
129                 //if necessary.
130                 //this.yield();
131 
132                 //ok... add this thread back into the thread pool
133                 ( (JetspeedThreadPoolService)TurbineServices
134                   .getInstance()
135                   .getService( ThreadPoolService.SERVICE_NAME ) )
136                     .release( this );
137                 
138             
139                 //if the runnable == null wait because it has been not been
140                 //directly assigned a task.. 
141                 if ( this.getRunnable() == null ) {
142                
143                     try {
144                         this.wait();
145                     } catch (InterruptedException e) {
146                         //this is a normal situation.  
147                         //the DaemonFactory may want to stop this thread form 
148                         //sleeping and call interrupt() on this thread.
149                     } catch ( Throwable t ) {
150                         logger.error("Throwable",  t);
151                         //continue;
152                     }
153 
154                 }
155 
156             }
157 
158             
159             if ( this.getRunnable() != null ) {
160                 this.setRunning( true );
161 
162                 try {
163                     
164                     this.getRunnable().run();
165 
166                 } catch ( Throwable t ) {
167                     logger.error( "A problem occured while trying to run your thread", t );
168                 }
169                     
170             }
171             
172         }
173         
174     }
175     
176     //misc getters/setters
177 
178     /***
179      * Set the Runnable process to execute
180      *
181      * @param runnable the Object to execute
182      */
183     public void setRunnable( Runnable runnable ) {
184         this.runnable = runnable;
185     }
186 
187     /***
188      * Get the Runnable process executing
189      *
190      * @return the Object executed by this thread
191      */
192     public Runnable getRunnable() {
193         return this.runnable;
194     }
195     
196     /***
197      * Test whether the thread is currently executing a process
198      *
199      * @return the status of this thread. If true, the thread is currently 
200      * executing a Runnable process, if false it's waiting for a new process
201      */
202     private boolean isRunning() {
203         return this.running;
204     }
205     
206     /***
207      * Set the running status of this thread.
208      *
209      * @return the status of this thread
210      */
211     private void setRunning( boolean running ) {
212         this.running = running;
213     }
214     
215     /***
216      * Get the numeric identifier of this thread
217      *
218      * @return the identifier of the thread
219      */
220     public int getId() {
221         return this.id;
222     }
223 }