deweese     01/08/06 08:35:13

  Modified:    sources/org/apache/batik/ext/awt/image/rendered
                        LRUCache.java
               sources/org/apache/batik/util RunnableQueue.java
  Added:       sources/org/apache/batik/util DoublyLinkedList.java
               test-sources/org/apache/batik/util RunnableQueueTest.java
                        ThreadPounder.java
  Log:
  1) Generic DoublyLinkedList class (used by LRU and now RunnableQueue).
  2) Updated version of RunnableQueue.
  3) ThreadPounder utility class that tries to get a bunch of threads to
     start as close to the same time as possible, presumably to 'pound'
     on a supposedly thread safe interface.
  4) RunnableQueueTest start of a test for the RunnableQueue class.
     Currently this really isn't very good (it takes a lot of 'human'
     work to make sense of the output....).
  
  Revision  Changes    Path
  1.4       +29 -117   
xml-batik/sources/org/apache/batik/ext/awt/image/rendered/LRUCache.java
  
  Index: LRUCache.java
  ===================================================================
  RCS file: 
/home/cvs/xml-batik/sources/org/apache/batik/ext/awt/image/rendered/LRUCache.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- LRUCache.java     2001/07/18 22:04:53     1.3
  +++ LRUCache.java     2001/08/06 15:35:13     1.4
  @@ -8,7 +8,10 @@
   
   package org.apache.batik.ext.awt.image.rendered;
   
  +import org.apache.batik.util.DoublyLinkedList;
  +
   public class LRUCache {
  +
       /**
        * Interface for object participating in the LRU Cache.  These
        * inform the object of key events in the status of the object in
  @@ -37,119 +40,27 @@
        * Interface for nodes in the LRU cache, basicly nodes in a doubly
        * linked list.
        */
  -     public class LRUNode {
  -             private LRUNode next = null;
  -             private LRUNode prev = null;
  -             private LRUObj  obj  = null;
  -                     
  -             public LRUNode getNext() { return next; }
  -             public LRUNode getPrev() { return prev; }
  -             public LRUObj  getObj()  { return obj; }
  -                                             
  -             protected void setNext(LRUNode newNext) { next = newNext; }
  -             protected void setPrev(LRUNode newPrev) { prev = newPrev; }
  -             protected void setObj (LRUObj  newObj)  { 
  +     public class LRUNode extends DoublyLinkedList.Node {
  +             private   LRUObj  obj  = null;
  +             public    LRUObj  getObj ()               { return obj; }
  +             protected void    setObj (LRUObj  newObj) { 
                        if (obj != null) obj.lruRemove();
   
                        obj = newObj;
                        if (obj != null) obj.lruSet(this);
                }
  -
  -                                             
  -             protected void unlink() {
  -                     // Unlink this node from it's current pos...
  -                     if (getNext() != null)
  -                             getNext().setPrev(getPrev());
  -                     if (getPrev() != null)
  -                             getPrev().setNext(getNext());
  -                     
  -                     setNext(null);
  -                     setPrev(null);
  -             }
  -                                             
  -             protected void insertBefore(LRUNode nde) {
  -                     // Already here...
  -                     if (this == nde) return;
  -                     
  -                     unlink();
  -                     
  -                     // Actually insert this node...
  -                     if (nde == null) {
  -                             // empty lst...
  -                             setNext(this);
  -                             setPrev(this);
  -                     } else {
  -                             setNext(nde);
  -                             setPrev(nde.getPrev());
  -                             nde.setPrev(this);
  -                if (getPrev() != null)
  -                    getPrev().setNext(this);
  -                     }
  -             }
  -     }
  -
  -    /**
  -     * A simple Doublly Linked list class, designed to avoid
  -     * O(n) behaviour on insert and delete.
  -     */
  -     public class LRUList {
  -
  -             private LRUNode head = null;
  -             private int     size = 0;
  -                     
  -             public LRUList() {}
  -                     
  -             public synchronized int getSize() { return size; }
  -                     
  -             public synchronized void empty() {
  -                     while(size > 0) pop();
  -             }
  -                     
  -             public LRUNode getHead() { return head; }
  -             public LRUNode getTail() { return head.getPrev(); }
  -                     
  -             public synchronized void touch(LRUNode nde) {
  -                     if (nde == null) return;
  -                     nde.insertBefore(head);
  -                     head = nde;
  -             }
  -
  -             public synchronized void add(LRUNode nde) {
  -                     touch(nde);
  -                     size++;
  -             }
  -                     
  -             public synchronized void remove(LRUNode nde) {
  -                     if (nde == null) return;
  -                     if (nde == head) head = nde.getNext();
  -                     nde.unlink();
  -                     size--;
  -             }
  -                     
  -             public synchronized LRUNode pop() {
  -                     if (head == null) return null;
  -                     
  -                     LRUNode nde = head;
  -                     
  -                     if (head.getNext() == head) head = null;  // Last node...
  -                     else                        head = head.getNext();
  -                     
  -                     nde.unlink();
  -                     size--;
  -                     return nde;
  -             }
        }
   
  -     private LRUList free    = null;
  -     private LRUList used    = null;
  +     private DoublyLinkedList free    = null;
  +     private DoublyLinkedList used    = null;
        private int     maxSize = 0;
                
        public LRUCache(int size) {
                if (size <= 0) size=1;
                maxSize = size;
                
  -             free = new LRUList();
  -             used = new LRUList();
  +             free = new DoublyLinkedList();
  +             used = new DoublyLinkedList();
                
                while (size > 0) {
                        free.add(new LRUNode());
  @@ -161,7 +72,7 @@
                return used.getSize();
        }
   
  -     public void setSize(int newSz) {
  +     public synchronized void setSize(int newSz) {
   
                if (maxSize < newSz) {  // list grew...
   
  @@ -171,7 +82,7 @@
                } else if (maxSize > newSz) {
   
                        for (int i=used.getSize(); i>newSz; i--) {
  -                             LRUNode nde = used.getTail();
  +                             LRUNode nde = (LRUNode)used.getTail();
                                used.remove(nde);
                                nde.setObj(null);
                        }
  @@ -180,30 +91,30 @@
                maxSize = newSz;
        }
   
  -     public void flush() {
  +     public synchronized void flush() {
                while (used.getSize() > 0) {
  -                     LRUNode nde = used.pop();
  +                     LRUNode nde = (LRUNode)used.pop();
                        nde.setObj(null);
                        free.add(nde);
                }
        }
   
  -     public void remove(LRUObj obj) {
  -             LRUNode nde = obj.lruGet();
  +     public synchronized void remove(LRUObj obj) {
  +             LRUNode nde = (LRUNode)obj.lruGet();
                if (nde == null) return;
                used.remove(nde);
                nde.setObj(null);
                free.add(nde);
        }
   
  -     public void touch(LRUObj obj) {
  -             LRUNode nde = obj.lruGet();
  +     public synchronized void touch(LRUObj obj) {
  +             LRUNode nde = (LRUNode)obj.lruGet();
                if (nde == null) return;
                used.touch(nde);
        }
   
  -     public void add(LRUObj obj) {
  -             LRUNode nde = obj.lruGet();
  +     public synchronized void add(LRUObj obj) {
  +             LRUNode nde = (LRUNode)obj.lruGet();
   
                // already linked in...
                if (nde != null) {
  @@ -212,24 +123,25 @@
                }
   
                if (free.getSize() > 0) {
  -                     nde = free.pop();
  +                     nde = (LRUNode)free.pop();
                        nde.setObj(obj);
                        used.add(nde);
                } else {
  -                     nde = used.getTail();
  +                     nde = (LRUNode)used.getTail();
                        nde.setObj(obj);
                        used.touch(nde);
                }
        }
   
  -     protected void print() {
  +     protected synchronized void print() {
                System.out.println("In Use: " + used.getSize() +
                                                   " Free: " + free.getSize());
  -             LRUNode cur = used.getHead();
  +             LRUNode nde = (LRUNode)used.getHead();
  +        if (nde == null) return;
                do {
  -                     System.out.println(cur.getObj());
  -                     cur = cur.getNext();
  -             } while (cur != used.getHead());
  +                     System.out.println(nde.getObj());
  +                     nde = (LRUNode)nde.getNext();
  +             } while (nde != used.getHead());
        }
   
   }
  
  
  
  1.3       +90 -129   xml-batik/sources/org/apache/batik/util/RunnableQueue.java
  
  Index: RunnableQueue.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/util/RunnableQueue.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- RunnableQueue.java        2001/08/06 12:33:35     1.2
  +++ RunnableQueue.java        2001/08/06 15:35:13     1.3
  @@ -16,36 +16,21 @@
    * invocation in a single thread.
    *
    * @author <a href="mailto:[EMAIL PROTECTED]";>Stephane Hillion</a>
  - * @version $Id: RunnableQueue.java,v 1.2 2001/08/06 12:33:35 hillion Exp $
  + * @version $Id: RunnableQueue.java,v 1.3 2001/08/06 15:35:13 deweese Exp $
    */
   public class RunnableQueue implements Runnable {
   
       /**
  -     * The lock used to wait for Runnable objects to be available.
  -     */
  -    protected Object invocationLock = new Object();
  -    
  -    /**
  -     * The lock used to suspend the queue execution.
  -     */
  -    protected Object suspendLock = new Object();
  -
  -    /**
        * whether this thread is suspended.
        */
       protected boolean suspended;
   
       /**
  -     * The Runnable objects list's head.
  +     * The Runnable objects list.
        */
  -    protected Link head;
  +    protected DoublyLinkedList list = new DoublyLinkedList();
   
       /**
  -     * The Runnable objects list's tail.
  -     */
  -    protected Link tail;
  -
  -    /**
        * The object which handle run events.
        */
       protected RunHandler runHandler;
  @@ -53,7 +38,7 @@
       /**
        * The current thread.
        */
  -    protected volatile Thread runnableQueueThread;
  +    protected Thread runnableQueueThread;
   
       /**
        * Creates a new RunnableQueue started in a new thread.
  @@ -62,9 +47,14 @@
        */
       public static RunnableQueue createRunnableQueue() {
           RunnableQueue result = new RunnableQueue();
  -        new Thread(result).start();
  -        while (result.getThread() == null) {
  -            Thread.yield();
  +        synchronized (result) {
  +            new Thread(result).start();
  +            while (result.getThread() == null) {
  +                try { 
  +                    result.wait();
  +                } catch (InterruptedException ie) {
  +                }
  +            }
           }
           return result;
       }
  @@ -73,48 +63,47 @@
        * Runs this queue.
        */
       public void run() {
  -        runnableQueueThread = Thread.currentThread();
  +        synchronized (this) {
  +            runnableQueueThread = Thread.currentThread();
  +            notify();
  +        }
  +        Link l;
  +        Runnable rable;
           try {
               while (!Thread.currentThread().isInterrupted()) {
  -                if (suspended) {
  -                    if (runHandler != null) {
  -                        runHandler.executionSuspended(this);
  -                    }
  -                    synchronized (suspendLock) {
  +                synchronized (this) {
  +                    if (suspended) {
  +                        if (runHandler != null) {
  +                            runHandler.executionSuspended(this);
  +                        }
                           while (suspended) {
  -                            suspendLock.wait();
  +                            wait();
                           }
  -                    }
  -                    if (runHandler != null) {
  -                        runHandler.executionResumed(this);
  +                        if (runHandler != null) {
  +                            runHandler.executionResumed(this);
  +                        }
                       }
  -                }
  -                if (head == null) {
  -                    synchronized (invocationLock) {
  -                        invocationLock.wait();
  +
  +                    l = (Link)list.pop();
  +                    if (l == null) {
  +                        wait();
  +                        continue; // start loop over again...
                       }
  +                    rable = l.runnable;
                   }
  -                Link l = head;
  +                rable.run();
  +                l.unlock();
                   synchronized (this) {
  -                    head = head.next;
  -                }
  -                l.runnable.run();
  -                if (l.isLock()) {
  -                    LockedLink ll = (LockedLink)l;
  -                    synchronized (l) {
  -                        while (!ll.isLocked()) {
  -                            l.wait();
  -                        }
  -                        l.notify();
  +                    if (runHandler != null) {
  +                        runHandler.runnableInvoked(this, rable);
                       }
                   }
  -                if (runHandler != null) {
  -                    runHandler.runnableInvoked(this, l.runnable);
  -                }
               }
           } catch (InterruptedException e) {
           } finally {
  -            runnableQueueThread = null;
  +            synchronized (this) {
  +                runnableQueueThread = null;
  +            }
           }
       }
   
  @@ -134,18 +123,11 @@
        */
       public synchronized void invokeLater(Runnable r) {
           if (runnableQueueThread == null) {
  -            throw new IllegalStateException("RunnableQueue not started");
  -        }
  -
  -        if (head == null) {
  -            head = tail = new UnlockedLink(r);
  -            synchronized (invocationLock) {
  -                invocationLock.notify();
  -            }
  -        } else {
  -            tail.next = new UnlockedLink(r);
  -            tail = tail.next;
  +            throw new IllegalStateException
  +                ("RunnableQueue not started or has exited");
           }
  +        list.push(new Link(r));
  +        notify();
       }
   
       /**
  @@ -158,39 +140,34 @@
        */
       public void invokeAndWait(Runnable r) throws InterruptedException {
           if (runnableQueueThread == null) {
  -            throw new IllegalStateException("RunnableQueue not started");
  +            throw new IllegalStateException
  +                ("RunnableQueue not started or has exited");
           }
           if (runnableQueueThread == Thread.currentThread()) {
               throw new IllegalStateException
                   ("Cannot be called from the RunnableQueue thread");
           }
   
  -        LockedLink l;
  +        LockableLink l = new LockableLink(r);
           synchronized (this) {
  -            if (head == null) {
  -                l = new LockedLink(r);
  -                head = tail = l;
  -                synchronized (invocationLock) {
  -                    invocationLock.notify();
  -                }
  -            } else {
  -                l = new LockedLink(r);
  -                tail.next = l;
  -                tail = tail.next;
  -            }
  +            list.push(l);
  +            notify();
           }
           l.lock();
       }
   
  +    public synchronized boolean isSuspended() { return suspended; }
  +
       /**
        * Suspends the execution of this queue.
        * @throws IllegalStateException if getThread() is null.
        */
  -    public void suspendExecution() {
  +    public synchronized void suspendExecution() {
           if (runnableQueueThread == null) {
  -            throw new IllegalStateException("RunnableQueue not started");
  +            throw new IllegalStateException
  +                ("RunnableQueue not started or has exited");
           }
  -
  +        
           suspended = true;
       }
   
  @@ -198,16 +175,15 @@
        * Resumes the execution of this queue.
        * @throws IllegalStateException if getThread() is null.
        */
  -    public void resumeExecution() {
  +    public synchronized void resumeExecution() {
           if (runnableQueueThread == null) {
  -            throw new IllegalStateException("RunnableQueue not started");
  +            throw new IllegalStateException
  +                ("RunnableQueue not started or has exited");
           }
   
  -        synchronized (suspendLock) {
  -            if (suspended) {
  -                suspended = false;
  -                suspendLock.notify();
  -            }
  +        if (suspended) {
  +            suspended = false;
  +            notify();
           }
       }
   
  @@ -220,29 +196,33 @@
        */
       public synchronized List getRunnableList() {
           if (runnableQueueThread == null) {
  -            throw new IllegalStateException("RunnableQueue not started");
  +            throw new IllegalStateException
  +                ("RunnableQueue not started or has exited");
           }
   
           List result = new LinkedList();
  -        Link l = head;
  -        while (l != null) {
  +        Link l, h;
  +        l = h = (Link)list.getHead();
  +        if (h==null) return result;
  +        do {
               result.add(l.runnable);
  -            l = l.next;
  -        }
  +            l = (Link)l.getNext();
  +        } while (l != h);
  +
           return result;
       }
   
       /**
        * Sets the RunHandler for this queue.
        */
  -    public void setRunHandler(RunHandler rh) {
  +    public synchronized void setRunHandler(RunHandler rh) {
           runHandler = rh;
       }
   
       /**
        * Returns the RunHandler or null.
        */
  -    public RunHandler getRunHandler() {
  +    public synchronized RunHandler getRunHandler() {
           return runHandler;
       }
   
  @@ -272,7 +252,7 @@
       /**
        * To store a Runnable.
        */
  -    protected  abstract static class Link {
  +    protected static class Link extends DoublyLinkedList.Node {
           
           /**
            * The Runnable.
  @@ -280,47 +260,23 @@
           public Runnable runnable;
   
           /**
  -         * The next link.
  -         */
  -        public Link next;
  -
  -        /**
            * Creates a new link.
            */
           public Link(Runnable r) {
               runnable = r;
           }
   
  -        /**
  -         * Whether the link is a lock.
  -         */
  -        public abstract boolean isLock();
  -    }
  -
  -    /**
  -     * To store a Runnable to invoke later.
  -     */
  -    protected static class UnlockedLink extends Link {
  -
  -        /**
  -         * Creates a new link.
  -         */
  -        public UnlockedLink(Runnable r) {
  -            super(r);
  -        }
  -
           /**
  -         * Whether the link is a lock.
  +         * unlock link and notify locker.  
  +         * Basic implementation does nothing.
            */
  -        public boolean isLock() {
  -            return false;
  -        }
  +        public void unlock() throws InterruptedException { return; }
       }
   
       /**
        * To store a Runnable with an object waiting for him to be executed.
        */
  -    protected static class LockedLink extends Link {
  +    protected static class LockableLink extends Link {
   
           /**
            * Whether this link is actually locked.
  @@ -330,18 +286,11 @@
           /**
            * Creates a new link.
            */
  -        public LockedLink(Runnable r) {
  +        public LockableLink(Runnable r) {
               super(r);
           }
   
           /**
  -         * Whether the link is a lock.
  -         */
  -        public boolean isLock() {
  -            return true;
  -        }
  -
  -        /**
            * Whether the link is actually locked.
            */
           public boolean isLocked() {
  @@ -355,6 +304,18 @@
               locked = true;
               notify();
               wait();
  +        }
  +
  +        /**
  +         * unlocks this link.
  +         */
  +        public synchronized void unlock() throws InterruptedException {
  +            while (!locked) {
  +                // Wait until lock is called...
  +                wait();
  +            }
  +            // Wake the locking thread...
  +            notify();
           }
       }
   }
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/util/DoublyLinkedList.java
  
  Index: DoublyLinkedList.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.util;
  
  /**
   * A simple Doubly Linked list class, designed to avoid
   * O(n) behaviour on insert and delete.
   */
  public class DoublyLinkedList {
  
      /**
       * Basic doubly linked list node interface.
       */
        public static class Node {
                private Node next = null;
                private Node prev = null;
                        
                public final Node getNext() { return next; }
                public final Node getPrev() { return prev; }
                                                
                protected final void setNext(Node newNext) { next = newNext; }
                protected final void setPrev(Node newPrev) { prev = newPrev; }
  
          /**
           * Unlink this node from it's current list...
           */
                protected final void unlink() {
                        if (getNext() != null)
                                getNext().setPrev(getPrev());
                        if (getPrev() != null)
                                getPrev().setNext(getNext());
                        
                        setNext(null);
                        setPrev(null);
                }
                                                
          /**
           * Link this node in, infront of nde (unlinks it's self
           * before hand if needed).
           * @param nde the node to link in before.
           */
                protected final void insertBefore(Node nde) {
                        // Already here...
                        if (this == nde) return;
  
                        if (getPrev() != null)
                  unlink();
                        
                        // Actually insert this node...
                        if (nde == null) {
                                // empty lst...
                                setNext(this);
                                setPrev(this);
                        } else {
                                setNext(nde);
                                setPrev(nde.getPrev());
                                nde.setPrev(this);
                  if (getPrev() != null)
                      getPrev().setNext(this);
                        }
                }
        }
  
  
      private Node head = null;
      private int  size = 0;
                        
      public DoublyLinkedList() {}
                        
      /**
       * Returns the number of elements currently in the list.
       */
      public synchronized int getSize() { return size; }
  
      /**
       * Removes all elements from the list.
       */
      public synchronized void empty() {
          while(size > 0) pop();
      }
                        
      /**
       * Get the current head element
       * @return The current 'first' element in list.
       */
      public Node getHead() { return head; }
      /**
       * Get the current tail element
       * @return The current 'last' element in list.
       */
      public Node getTail() { return head.getPrev(); }
  
      /**
       * Moves <tt>nde</tt> to the head of the list (equivilent to
       * remove(nde); add(nde); but faster.
       */
      public void touch(Node nde) {
          if (nde == null) return;
          nde.insertBefore(head);
          head = nde;
      }
  
      /**
       * Adds <tt>nde</tt> to the head of the list.
       * In perl this is called an 'unpop'.  <tt>nde</tt> should
       * not currently be part of any list.
       * @param nde the node to add to the list.
       */
      public void add(Node nde) {
          if (nde == null) return;
          nde.insertBefore(head);
          head = nde;
          size++;
      }
                
        /**
       * Removes nde from the list it is part of (should be this
       * one, otherwise results are undefined).  If nde is the
       * current head element, then the next element becomes head,
       * if there are no more elements the list becomes empty.
       * @param nde node to remove.
       */
      public void remove(Node nde) {
          if (nde == null) return;
          if (nde == head) {
              if (head.getNext() == head) 
                  head = null;  // Last node...
              else
                  head = head.getNext();
          }
          nde.unlink();
          size--;
      }
  
      /**
       * Removes 'head' from list and returns it. Returns null if list is empty.
       * @returns current head element, next element becomes head.
       */
      public Node pop() {
          if (head == null) return null;
                        
          Node nde = head;
          remove(head);
          return nde;
      }
  
      /**
       * Adds <tt>nde</tt> to tail of list
       */
      public void push(Node nde) {
          nde.insertBefore(head);
          if (head == null) head = nde;
          size++;
      }
  }
  
  
  
  
  1.1                  
xml-batik/test-sources/org/apache/batik/util/RunnableQueueTest.java
  
  Index: RunnableQueueTest.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.util;
  
  import org.apache.batik.test.AbstractTest;
  import org.apache.batik.test.DefaultTestReport;
  import org.apache.batik.test.TestReport;
  
  import java.util.List;
  import java.util.ArrayList;
  import java.util.Random;
  
  public class RunnableQueueTest extends AbstractTest {
  
      public int nThreads;
      public int activeThreads;
  
      /**
       * Constructor
       * @param nThreads number of runnables to queue
       * @param sync     Should requests be made synchronously (from
       *                 different threads).
       */
      public RunnableQueueTest(int nThreads, boolean sync) {
          this.nThreads = nThreads;
      }
          
          /**
           * Returns this Test's name
           */
          public String getName() {
              return "RunnableQueue Stress Test";
          }
  
      /**
       * This method will only throw exceptions if some aspect
       * of the test's internal operation fails.
       */
      public TestReport runImpl() throws Exception {
          RunnableQueue rq = RunnableQueue.createRunnableQueue();
  
          List l = new ArrayList(nThreads);
          Random rand = new Random(2345);
          for (int i=0; i<nThreads; i++) {
              Runnable rqRable = new RQRable(i, rand.nextInt(50));
              l.add(new TPRable(rq, i, rand.nextBoolean(),
                                rand.nextInt(1000), 20, rqRable));
          }
          synchronized (this) {
              ThreadPounder tp = new ThreadPounder(l);
              tp.start();
              activeThreads = nThreads;
              while (activeThreads != 0) {
                  rq.suspendExecution();
                  System.out.println("Suspended");
                  wait(rand.nextInt(100));
                  if (activeThreads == 0) break;
                  System.out.println("Resuming");
                  rq.resumeExecution();
                  wait(rand.nextInt(500));
              }
          }
  
          System.exit(0);
          return null;
      }
  
      public class TPRable implements Runnable {
          RunnableQueue rq;
          int           idx;
          boolean       invokeAndWait;
          long          repeatDelay;
          int           count;
          Runnable      rqRable;
  
          TPRable(RunnableQueue rq, int idx, 
                  boolean invokeAndWait,
                  long    repeatDelay, int count,
                  Runnable rqRable) {
              this.rq            = rq;
              this.idx           = idx;
              this.invokeAndWait = invokeAndWait;
              this.repeatDelay   = repeatDelay;
              this.count         = count;
              this.rqRable       = rqRable;
          }
  
          public void run() {
              try {
                  while (count-- != 0) {
                      if (invokeAndWait) {
                          System.out.println("     InvW #" + idx);
                          rq.invokeAndWait(rqRable);
                          System.out.println("Done InvW #" + idx);
                      } else {
                          synchronized (rqRable) {
                              System.out.println("     InvL #" + idx);
                              rq.invokeLater(rqRable);
                              System.out.println("Done InvL #" + idx);
                              rqRable.wait();
                          }
                      }
                      if (repeatDelay < 0) 
                          break;
                      Thread.sleep(repeatDelay);
                  }
              } catch (InterruptedException ie) {
              }
              synchronized(RunnableQueueTest.this) {
                  activeThreads--;
                  RunnableQueueTest.this.notify();
              }
          }
      }
  
      public static class RQRable implements Runnable {
          int  idx;
          long dur;
  
          RQRable(int idx, long dur) {
              this.idx = idx;
              this.dur = dur;
          }
  
          public void run() {
              try {
                  System.out.println("      B Rable #" + idx);
                  Thread.sleep(dur);
                  System.out.println("      E Rable #" + idx);
                  synchronized (this) {
                      notify();
                  }
              } catch (InterruptedException ie) { }
          }
      }
  
      public static void main(String []args) {
          RunnableQueueTest rqt = new RunnableQueueTest(20, false);
          try {
              rqt.runImpl();
          } catch (Exception e) {
              e.printStackTrace();
          }
      }
  }
  
  
  
  1.1                  xml-batik/test-sources/org/apache/batik/util/ThreadPounder.java
  
  Index: ThreadPounder.java
  ===================================================================
  /*****************************************************************************
   * Copyright (C) The Apache Software Foundation. All rights reserved.        *
   * ------------------------------------------------------------------------- *
   * This software is published under the terms of the Apache Software License *
   * version 1.1, a copy of which has been included with this distribution in  *
   * the LICENSE file.                                                         *
   *****************************************************************************/
  
  package org.apache.batik.util;
  
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Iterator;
  import java.util.Collections;
  import java.util.Random;
  
  /**
   * The purpose of this class is to invoke a series of runnables as
   * closely to synchronously as possible.  It does this by starting 
   * a thread for each one, getting the threads into there run method,
   * then quickly running through (in random order) and notifying each
   * thread.
   */
  public class ThreadPounder {
      List runnables;
      Object [] threads;
      Object lock = new Object();
  
      public ThreadPounder(List runnables)  
          throws InterruptedException {
          this(runnables, new Random(1234));
      }
  
      public ThreadPounder(List runnables, Random rand) 
          throws InterruptedException {
          this.runnables = new ArrayList(runnables);
          Collections.shuffle(this.runnables, rand);
          threads = new Object[this.runnables.size()];
          int i=0;
          Iterator iter= this.runnables.iterator();
          synchronized (lock) {
              while (iter.hasNext()) {
                  Thread t = new SyncThread((Runnable)iter.next());
                  t.start();
                  lock.wait();
                  threads[i] = t;
                  i++;
              }
          }
      }
  
      public void start() {
          synchronized(this) {
              this.notifyAll();
          }
  
      }
  
      class SyncThread extends Thread {
          Runnable toRun;
          public long runTime;
          public SyncThread(Runnable toRun) {
              this.toRun = toRun;
          }
  
          public void run() {
              try {
                  synchronized (ThreadPounder.this) {
                      synchronized (lock) {
                          // Let pounder know I'm ready to go
                          lock.notify();
                      }
                      // Wait for pounder to wake me up.
                      ThreadPounder.this.wait();
                  }
                  toRun.run();
              } catch (InterruptedException ie) {
              }
          }
      }
  
      public static void main(String [] str) { 
          List l = new ArrayList(20);
          for (int i=0; i<20; i++) {
              final int x = i;
              l.add(new Runnable() {
                      public void run() {
                          System.out.println("Thread " + x);
                      }
                  });
          }
  
          try { 
              ThreadPounder tp = new ThreadPounder(l);
              System.out.println("Starting:" );
              tp.start();
              System.out.println("All Started:" );
          } catch (InterruptedException ie) {
              ie.printStackTrace();
          }
      }
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to