Hello Larry,

the version of the ThreadQueue is a bit outdated.
The version you have has no getRunningThreads() method.
This is need for compatibility. And there was a bug in
remove(Listener) which is fixed by now.
I attach the current ThreadQueue.

Now to your problem:

The Listeners are in for compatibility and you are right
they get there kick when the WORKER_STAY_ALIVE_TIME has
expired. But once again: These Listeners _do_ _not_ help
you! You want to know when the last job has ended, not
when there are no more running Threads. We discussed this
already.

I would suggest the following solution on your side
to archive the desired effect:

<code>

Graphics2D destination = ... // from outer space

LayerViewPanel layerViewPanel = ... // from outer space

RenderingManager renderingManager =
  layerViewPanel.getRenderingManager();

ThreadQueue defaultThreadQueue =
  renderingManager.getDefaultRendererThreadQueue();

// add all the Renderer Runnables to the ThreadQueue
renderingManager.renderAll();

final boolean [] locked = { true };

// because defaultThreadQueue does its jobs
// one after each other append a 'wakeup' Runnable ...

defaultThreadQueue.add(new Runnable() {
  public void run() {
    synchronized (locked) {
      locked[0] = false;
      locked.notify();
    }
  }
});

try {
  synchronized (locked) {
    // you could simply write
    // "while (locked[0]) locked.wait();"
    // but following is more defensive
    int count = 0;
    while (locked[0] && count++ < 10)
      locked.wait(10000L);
  }
}
catch (InterruptedException ie) {
}

renderingManager.copyTo(destination);

</code>

But as I said earlier, this only works on
the defaultRenderingThreadQueue and therefore
its only an interim solution. The
WMS/DB ThreadQueue is private and a true
parallel ThreadQueue.

My goal is to add a renderAllSynchronized()
to RenderingManager that used the above
Runnable/unlock trick. The secret WMS/DB
will be eliminated (or better the default one
and the WMS/DB ThreadQueue will become the
default). This is doable with the
RunnableArrayList class I posted a while
ago, which simulates the single thread
default ThreadQueue. But one step after
the other ...

Regards, Sascha


Larry Becker schrieb:
> Sascha,
> 
>  I have reached a point where I need some help with the new
> ThreadQueue implementation.  I have modified my code that calls
> getRunningThreads to use the Listener with the
> allRunningThreadsFinished method instead.  This was much cleaner and
> worked fine until I replaced ThreadQueue with your version.  The
> problem I seem to be having is that the method doesn't fire until
> after the 5 second WORKER_STAY_ALIVE_TIME has expired.  Can you
> explain what I should be doing or modify the code so that it fires
> when there are no more jobs waiting?
> 
> I have attached the version of ThreadQueue.java that I have been using
> in case it is outdated.
> 
> thanks,
> Larry Becker
> 
> 
> ------------------------------------------------------------------------
> 
> -------------------------------------------------------------------------
> This SF.net email is sponsored by DB2 Express
> Download DB2 Express C - the FREE version of DB2 express and take
> control of your XML. No limits. Just data. Click to get it now.
> http://sourceforge.net/powerbar/db2/
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Jump-pilot-devel mailing list
> Jump-pilot-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel
/*
 * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI 
 * for visualizing and manipulating spatial features with geometry and attributes.
 *
 * Copyright (C) 2003 Vivid Solutions 
 * Copyright (C) 2007 Intevation GmbH
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * Suite #1A
 * 2328 Government Street
 * Victoria BC  V8T 5G5
 * Canada
 *
 * (250)385-6040
 * www.vividsolutions.com
 */
package com.vividsolutions.jump.workbench.ui.renderer;

import java.util.LinkedList;
import java.util.ArrayList;

/**
 * This thread queue executes at maximum N Runnables in parallel
 * were N is a given number of worker threads that should be used.
 * If N threads are running and busy each further incoming 
 * Runnable is queued until one of the threads has finished its current job.
 * If a worker thread becomes idle (no more job in the queue)
 * it is hold alive for 5 seconds. If during this period of time 
 * no new Runnable is enqueued the worker thread dies.
 *
 * @author Sascha L. Teichmann ([EMAIL PROTECTED])
 */
public class ThreadQueue
{
	/** The time a worker thread stays alive if idle */
	public static final long WORKER_STAY_ALIVE_TIME = 5000L;

	/**
	 * Worker thread. Fetches Runnable from the surrounding 
	 * ThreadQueue instance.
	 */
	protected class Worker 
	extends         Thread
	{
		public void run() {
			try {
				for (;;) {
					Runnable runnable;

					synchronized (queuedRunnables) {
						if (queuedRunnables.isEmpty()) {
							++waitingThreads;
							try {
								queuedRunnables.wait(WORKER_STAY_ALIVE_TIME);
							}
							catch (InterruptedException ie) {
							}
							finally {
								--waitingThreads;
							}

							// if still empty -> die!
							if (queuedRunnables.isEmpty())
								break;
						}
						if (disposed)
							break;
						runnable = (Runnable)queuedRunnables.remove();
					} // synchronized queuedRunnables

					try {
						runnable.run();
					}
					catch (Exception e) {
						e.printStackTrace();
					}
				} // for (;;)
			}
			finally { // guarantee that counter goes down
				boolean allRunningThreadsFinished;
				synchronized (runningThreads) {
					allRunningThreadsFinished = --runningThreads[0] == 0;
				}
				if (allRunningThreadsFinished)
					fireAllRunningThreadsFinished();
			}
		}
	} // class Worker

	/**
	 * If the number of running threads goes down to zero
	 * implementations of this interface are able to be informed.
	 */
	public interface Listener {
		void allRunningThreadsFinished();
	} // interface Listener

	/** Number of running threads */
	protected int [] runningThreads = new int[1];

	/** max. Number of threads running parallel */
	protected int maxRunningThreads;

	/** Number of threads that are currently idle */
	protected int waitingThreads;

	/** The queue of Runnables jobs waiting to be run */
	protected LinkedList queuedRunnables;

	/** Singals that the ThreadQueue is going to quit */
	protected boolean disposed;

	/** List of Listeners */
	protected ArrayList listeners = new ArrayList();

	/**
	 * Creates a ThreadQueue with one worker thread.
	 */
	public ThreadQueue() {
		this(1);
	}

	/** Creates a ThreadQueue with a given number of worker threads.
	 * @param maxRunningThreads the max. number of threads to be run parallel.
	 */
	public ThreadQueue(int maxRunningThreads) {
		this.maxRunningThreads = Math.max(1, maxRunningThreads);
		queuedRunnables = new LinkedList();
	}

	/**
	 * Adds a Listener to this ThreadQueue.
	 * @param listener the listener to add.
	 */
	public synchronized void add(Listener listener) {
		if (listener != null)
			listeners.add(listener);
	}

	/**
	 * Removes a Listener from this ThreadQueue.
	 * @param listener the listener to be removed.
	 */
	public synchronized void remove(Listener listener) {
		if (listener != null)
			listeners.remove(listener);
	}

	/**
	 * Informs Listeners of the fact that the number of running threads
	 * went to zero.
	 */
	protected void fireAllRunningThreadsFinished() {
		ArrayList copy;
		synchronized (this) { copy = new ArrayList(listeners); }
		for (int i = copy.size()-1; i >= 0; --i)
			((Listener)copy.get(i)).allRunningThreadsFinished();
	}


	/**
	 * The number of currently running worker threads.
	 * @return number of currently running worker threads.
	 */
	public int runningThreads() {
		synchronized (runningThreads) {
			return runningThreads[0];
		}
	}

	/**
	 * The number of currently running worker threads.
	 * Alias for runningThreads()
	 * @return number of currently running worker threads.
	 */
	public int getRunningThreads() {
		return runningThreads();
	}

	/**
	 * The number of currently waiting Runnables.
	 * @return number of currently waiting Runnables.
	 */
	public int waitingRunnables() {
		synchronized (runningThreads) {
			return queuedRunnables.size();
		}
	}

	/**
	 * The number of currently idle worker threads.
	 * @return number of currently idle worker threads.
	 */
	public int waitingThreads() {
		synchronized (queuedRunnables) {
			return waitingThreads;
		}
	}

	/**
	 * Adds a Runnables to the queue. It will be run in one
	 * of the worker threads.
	 * @param runnable The Runnables to add
	 */
	public void add(Runnable runnable) {
		int waiting;
		synchronized (queuedRunnables) {
			if (disposed)
				return;
			waiting = waitingThreads;
			queuedRunnables.add(runnable);
			queuedRunnables.notify();
		}  // synchronized (queuedRunnables)

		synchronized (runningThreads) {

			// if waitingThreads == 1 then
			// the queuedRunnables.notify() should have waked it up.

			if (waitingThreads < 2 && runningThreads[0] < maxRunningThreads) {
				++runningThreads[0];
				Worker w = new Worker();
				w.setDaemon(true);
				w.start();
			}
		} // synchronized (runningThreads)
	}

	/**
	 * Empties the queue of waiting Runnables.
	 */
	public void clear() {
		synchronized (queuedRunnables) {
			queuedRunnables.clear();
		}
	}

	/**
	 * Shuts down the ThreadQueue.
	 */
	public void dispose() {
		synchronized (queuedRunnables) {
			disposed = true;
			queuedRunnables.clear();
			// wakeup idle threads
			queuedRunnables.notifyAll();
		}
		synchronized (this) {
			listeners.clear();
		}
	}
}
// end of file
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Jump-pilot-devel mailing list
Jump-pilot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jump-pilot-devel

Reply via email to