/* * Copyright 2000-2001,2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.jetspeed.services.threadpool; // turbine stuff import org.apache.jetspeed.services.logging.JetspeedLogFactoryService; import org.apache.jetspeed.services.logging.JetspeedLogger; import org.apache.turbine.services.TurbineServices; /** * A thread that is used to process Runnables. This thread will wait until it is * notified by another thread that it needs processing. However it will only * process if getRunnable != null. * * @author <a href="mailto:burton@apache.org">Kevin A. Burton</a> * @author <a href="mailto:sgala@apache.org">Santiago Gala</a> */ public class RunnableThread extends Thread { /** * Static initialization of the logger for this class */ private static final JetspeedLogger logger = JetspeedLogFactoryService .getLogger(RunnableThread.class.getName()); private boolean running = false; private static int next_id = 0; /** * Increment a counter so that we can identify threads easily. */ private static synchronized int getNextId() { return ++next_id; }; private int id = 0; /** * The runnable that you want to process */ private Runnable runnable = null; public RunnableThread() { super(); this.setDaemon(true); } /** * Creates a new Thread in the specified threadgroup * * @param tg * the Threadgroup which will contain the new Thread */ public RunnableThread(ThreadGroup tg) { super(tg, "Provisory"); this.id = getNextId(); super.setName("RunnableThread:" + this.id); this.setPriority(Thread.MIN_PRIORITY); this.setDaemon(true); } /** * Creates a new Thread in the specified threadgroup and assigns it an id. * * @param tg * the Threadgroup which will contain the new Thread * @param id * an identifier for the new Thread */ public RunnableThread(ThreadGroup tg, int id) { super(tg, "RunnableThread:" + id); this.setPriority(Thread.MIN_PRIORITY); this.setDaemon(true); this.id = id; } /** * Processes the Runnable object assigned to it, whenever one is available */ public void run() { /* * FIXME: move to a static class variable to allow for pool shutdown */ boolean poolrunning = true; while (poolrunning) { // On creation, we are idle. // So, add ourselves to the Pool. // Next times we come here, we are just finished // one run... this.setRunning(false); this.setRunnable(null); synchronized (this) { if (this.getPriority() != JetspeedThreadPoolService.DEFAULT_THREAD_PRIORITY) { // give the thread back it's default priority. this.setPriority(JetspeedThreadPoolService.DEFAULT_THREAD_PRIORITY); } // SGP I don't think it is needed. The scheduler will do its job // and the thread will be released sooner. Later, it will wait // until the Pool reuses it. Correct me if I'm wrong // but please comment the reasons, as I don't get it :) // yield this thread so that other threads can now execute // if necessary. // this.yield(); // ok... add this thread back into the thread pool ((JetspeedThreadPoolService) TurbineServices.getInstance().getService( ThreadPoolService.SERVICE_NAME)).release(this); // if the runnable == null wait because it has been not been // directly assigned a task.. if (this.getRunnable() == null) { try { this.wait(); } catch (InterruptedException e) { // this is a normal situation. // the DaemonFactory may want to stop this thread form // sleeping and call interrupt() on this thread. } catch (Throwable t) { logger.error("Throwable", t); // continue; } } } if (this.getRunnable() != null) { this.setRunning(true); try { this.getRunnable().run(); } catch (Throwable t) { logger.error("A problem occured while trying to run your thread", t); } } } } // misc getters/setters /** * Set the Runnable process to execute * * @param runnable * the Object to execute */ public void setRunnable(Runnable runnable) { this.runnable = runnable; } /** * Get the Runnable process executing * * @return the Object executed by this thread */ public Runnable getRunnable() { return this.runnable; } /** * Test whether the thread is currently executing a process * * @return the status of this thread. If true, the thread is currently * executing a Runnable process, if false it's waiting for a new * process */ private boolean isRunning() { return this.running; } /** * Set the running status of this thread. * * @return the status of this thread */ private void setRunning(boolean running) { this.running = running; } /** * Get the numeric identifier of this thread * * @return the identifier of the thread */ public long getId() { return this.id; } }