Hi together,

as some of you may already know i have my dislikes against
ThreadQueue [1] (Hi, Larry!) see my mail [2]

a - It forks a new thread for any Runnable it processes.
b - It has an ugly busy wait loop inside.
c - The event listener for empty queue fires to often.
d - The default ThreadQueue is some kind of thread serializer.
e - The DB/WMS ThreadQueue has no public access.

Now I've written a sub class of ThreadQueue: SingleThreadQueue
(see attachment). This one deals with the issues a, b and d.
I also attached a patch against RenderingManager [3] to handle e.

The new class (to be placed in package
com.vividsolutions.jump.workbench.ui.renderer) is a drop-in
replacement for the default ThreadQueue in RenderingManager.
Not for the ThreadQueue that handles the DB/WMS layers.

Because Jon limited the number of parallel threads in default
queue to 1 I see no reason why to fork a new thread for each
Runnable it processes. Thread creation/shutdown is fairly
expensive. Instead a single background thread is started
which processes the Runnables one by one. If the thread
is idle for 30 secs it shuts itself down. If you have a lot
of (non-WMS/BB) layers this should improve performance
and save some resources. The processing itself is done
with a monitor (synchronized/wait/notify) so there is no
busy wait any more.

The DB/WMS ThreadQueue (real parallel threads) is left untouched
for the moment. Depending on my personal schedule I will send
a patch against this one too. Preliminary code with thread pooling
exists but it needs a bit more testing.

Find attached the new class and patches against RenderingManager and
the old ThreadQueue to bring it to work.

Comments are very welcome. :-)

Kind regrads,
  Sascha

[1] com.vividsolutions.jump.workbench.ui.renderer.ThreadQueue
[2]
http://sourceforge.net/mailarchive/message.php?msg_name=4653389E.6000706%40intevation.de
[3] com.vividsolutions.jump.workbench.ui.renderer.RenderingManager
Index: ./src/com/vividsolutions/jump/workbench/ui/renderer/RenderingManager.java
===================================================================
RCS file: 
/cvsroot/jump-pilot/openjump/src/com/vividsolutions/jump/workbench/ui/renderer/RenderingManager.java,v
retrieving revision 1.6
diff -u -r1.6 RenderingManager.java
--- ./src/com/vividsolutions/jump/workbench/ui/renderer/RenderingManager.java   
22 May 2007 18:47:12 -0000      1.6
+++ ./src/com/vividsolutions/jump/workbench/ui/renderer/RenderingManager.java   
24 May 2007 04:10:30 -0000
@@ -77,7 +77,7 @@
         * non-database layers in parallel. In fact, it will make the GUI less
         * responsive. [Jon Aquino]
         */
-       private ThreadQueue defaultRendererThreadQueue = new ThreadQueue(1);
+       private ThreadQueue defaultRendererThreadQueue = new 
SingleThreadQueue();
 
        /**
         * WMS and database processing are done on the server side, so allow 
these
@@ -294,6 +294,10 @@
                return defaultRendererThreadQueue;
        }
 
+       public ThreadQueue getMultiRendererThreadQueue() {
+               return multiRendererThreadQueue;
+       }
+
        public void dispose() {
                repaintTimer.stop();
                defaultRendererThreadQueue.dispose();
@@ -334,4 +338,4 @@
         contentIDToRendererMap.remove(contentID);
     }
     
-}
\ No newline at end of file
+}
Index: ./src/com/vividsolutions/jump/workbench/ui/renderer/ThreadQueue.java
===================================================================
RCS file: 
/cvsroot/jump-pilot/openjump/src/com/vividsolutions/jump/workbench/ui/renderer/ThreadQueue.java,v
retrieving revision 1.1
diff -u -r1.1 ThreadQueue.java
--- ./src/com/vividsolutions/jump/workbench/ui/renderer/ThreadQueue.java        
16 Jun 2005 22:50:38 -0000      1.1
+++ ./src/com/vividsolutions/jump/workbench/ui/renderer/ThreadQueue.java        
24 May 2007 04:09:15 -0000
@@ -47,6 +47,10 @@
     private Vector queuedRunnables = new Vector();
     private int maxRunningThreads;
 
+               public ThreadQueue() {
+                       this(1);
+               }
+
     public ThreadQueue(final int maxRunningThreads) {
         this.maxRunningThreads = maxRunningThreads;
     }
@@ -95,7 +99,7 @@
     public static interface Listener {
         public void allRunningThreadsFinished();
     }
-    private void fireAllRunningThreadsFinished() {
+    protected void fireAllRunningThreadsFinished() {
        //new ArrayList to avoid ConcurrentModificationException [Jon Aquino]
         for (Iterator i = new ArrayList(listeners).iterator(); i.hasNext(); ) {
             Listener listener = (Listener) i.next();
/*
 * 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.
 */
package com.vividsolutions.jump.workbench.ui.renderer;

import java.util.LinkedList;

/**
 * This special ThreadQueue uses a single thread to do all
 * the rendering instead of forking a new one for each 
 * incomming Runnable. If the internal queue stays empty
 * for TIME_TO_WAIT milli seconds the thread shuts itself down.
 *
 * @author Sascha L. Teichmann ([EMAIL PROTECTED])
 */
public class SingleThreadQueue
extends      ThreadQueue
{
	/**
	 * This is the time to wait before the processing thread ends.
	 * (30 secs)
	 */
	public static final long TIME_TO_WAIT = 30000L;

	protected class QThread extends Thread
	{
		protected LinkedList queue;

		public QThread() {
			queue = new LinkedList();
		}

		public int runningThreads() {
			synchronized (queue) {
				return queue.size();
			}
		}

		public void add(Runnable runnable) {
			synchronized (queue) {
				queue.add(runnable);
				queue.notify();
			}
		}

		public void clear() {
			synchronized (queue) {
				queue.clear();
			}
		}

		public void run() {
			boolean done = false;
			do { // while (!done)
				try {
					for (;;) {
						synchronized (SingleThreadQueue.this) {
							if (SingleThreadQueue.this.disposed) {
								done = true;
								break;
							}
						}
						Runnable runnable;
						synchronized (queue) {
							if (queue.isEmpty()) {
								queue.wait(TIME_TO_WAIT);
								if (queue.isEmpty()) {
									synchronized (SingleThreadQueue.this) {
										// This may look odd but it guarantees that
										// no add() is done while checking for emptiness.
										if (queue.isEmpty())
											break;
									}
								}
							}
							runnable = (Runnable)queue.remove();
							if (runnable == null)
								break;
						} // synchronized queue
						try {
							runnable.run();
						}
						catch (Exception e) {
							e.printStackTrace();
						}
					} // for (;;)
				}
				catch (InterruptedException ie) {
					done = true;
				}
				finally {
					synchronized (queue) {
						if (queue.isEmpty())
							done = true;
					}
					synchronized (SingleThreadQueue.this) {
						SingleThreadQueue.this.thread = null;
					}
				}
			}
			while (!done);
			SingleThreadQueue.this.fireAllRunningThreadsFinished();
		}

	} // class QThread

	protected boolean disposed;
	protected QThread thread;

	public SingleThreadQueue() {
	}

	public synchronized void clear() {
		if (thread != null)
			thread.clear();
	}

	public synchronized void add(Runnable runnable) {
		if (disposed)
			return;

		if (thread == null) {
			thread = new QThread();
			thread.setDaemon(true);
			thread.start();
		}

		thread.add(runnable);
	}

	public synchronized int runningThreads() {
		return thread == null ? 0 : thread.runningThreads();
	}

	public synchronized void dispose() {
		clear();
		disposed = true;
	}
}
// 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