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