001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.batik.util;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022: import java.util.Iterator;
023: import java.util.Collections;
024: import java.util.Random;
025:
026: /**
027: * The purpose of this class is to invoke a series of runnables as
028: * closely to synchronously as possible. It does this by starting
029: * a thread for each one, getting the threads into there run method,
030: * then quickly running through (in random order) and notifying each
031: * thread.
032: */
033: public class ThreadPounder {
034: List runnables;
035: Object[] threads;
036: Object lock = new Object();
037:
038: public ThreadPounder(List runnables) throws InterruptedException {
039: this (runnables, new Random(1234));
040: }
041:
042: public ThreadPounder(List runnables, Random rand)
043: throws InterruptedException {
044: this .runnables = new ArrayList(runnables);
045: Collections.shuffle(this .runnables, rand);
046: threads = new Object[this .runnables.size()];
047: int i = 0;
048: Iterator iter = this .runnables.iterator();
049: synchronized (lock) {
050: while (iter.hasNext()) {
051: Thread t = new SyncThread((Runnable) iter.next());
052: t.start();
053: lock.wait();
054: threads[i] = t;
055: i++;
056: }
057: }
058: }
059:
060: public void start() {
061: synchronized (this ) {
062: this .notifyAll();
063: }
064:
065: }
066:
067: class SyncThread extends Thread {
068: Runnable toRun;
069: public long runTime;
070:
071: public SyncThread(Runnable toRun) {
072: this .toRun = toRun;
073: }
074:
075: public void run() {
076: try {
077: synchronized (ThreadPounder.this ) {
078: synchronized (lock) {
079: // Let pounder know I'm ready to go
080: lock.notify();
081: }
082: // Wait for pounder to wake me up.
083: ThreadPounder.this .wait();
084: }
085: toRun.run();
086: } catch (InterruptedException ie) {
087: }
088: }
089: }
090:
091: public static void main(String[] str) {
092: List l = new ArrayList(20);
093: for (int i = 0; i < 20; i++) {
094: final int x = i;
095: l.add(new Runnable() {
096: public void run() {
097: System.out.println("Thread " + x);
098: }
099: });
100: }
101:
102: try {
103: ThreadPounder tp = new ThreadPounder(l);
104: System.out.println("Starting:");
105: tp.start();
106: System.out.println("All Started:");
107: } catch (InterruptedException ie) {
108: ie.printStackTrace();
109: }
110: }
111: }
|