Example #1
0
  public static void main(String[] args) {

    // Sys.eval("J2ME.emitCheckArrayStore = false;");
    // Sys.eval("J2ME.emitCheckArrayBounds = false;");

    size = 32;

    begin();
    start = JVM.monotonicTimeMillis();
    createObjectArrays();
    createPrimitiveArrays();
    writeByteArrayOutputStream();
    concatStrings();
    getBytes();
    synch();
    hashtable();
    arrayTypeCheck();
    finish("startup");

    size = 32 * 64;

    long start = JVM.monotonicTimeMillis();
    begin();
    createObjectArrays();
    finish("createObjectArrays");

    begin();
    createPrimitiveArrays();
    finish("createPrimitiveArrays");

    begin();
    writeByteArrayOutputStream();
    finish("writeByteArrayOutputStream");

    begin();
    concatStrings();
    finish("concatStrings");

    begin();
    getBytes();
    finish("getBytes");

    begin();
    synch();
    finish("synchronize");

    begin();
    hashtable();
    finish("hashtable");

    begin();
    arrayTypeCheck();
    finish("arrayTypeCheck");

    System.out.println();
    System.out.println("Total: " + (JVM.monotonicTimeMillis() - start));
  }
Example #2
0
  /**
   * Returns the value of the user clock skew in milliseconds. Returned is the deviation of the user
   * clock from the monotonic clock accumulated since the previous invocation of this method in this
   * task. Deviations below the <code>SKEW_THRESHOLD</code> are not reported. They are accumulated
   * until they exceed the threshold.
   *
   * @return the user clock skew
   */
  static long userClockSkew() {
    long newDelta = System.currentTimeMillis() - JVM.monotonicTimeMillis();
    long oldDelta = userClockOffset - monotonicClockOffset;
    long skew = newDelta - oldDelta;
    if (Math.abs(skew) < SKEW_THRESHOLD) {
      skew = 0;
    }

    userClockOffset += skew;
    return skew;
  }
Example #3
0
  /**
   * Schedule the specified timer task for execution at the specified time with the specified
   * period, in milliseconds. If period is positive, the task is scheduled for repeated execution;
   * if period is zero, the task is scheduled for one-time execution. Time is specified in
   * Date.getTime() format. This method checks timer state, task state, and initial execution time,
   * but not period.
   *
   * @param task task to be scheduled.
   * @param userTime the user time at which task is to be executed or <tt>null</tt> if the delay is
   *     specified
   * @param delay the delay in milliseconds before the task execution
   * @param period time in milliseconds between successive task executions.
   * @param isUserClock true if the time is bound to user clock
   * @throws IllegalArgumentException if <tt>time()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, timer was cancelled,
   *     or timer thread terminated.
   */
  private void sched(TimerTask task, Date userTime, long delay, long period) {
    final boolean isUserClock = userTime != null;

    long time;

    if (isUserClock) {
      long t = userTime.getTime();
      if (t < 0) {
        throw new IllegalArgumentException("Illegal execution time.");
      }
      time = Timer.userTimeFromStart(t);
    } else {
      time = Timer.monotonicTimeFromStart(JVM.monotonicTimeMillis() + delay);
    }

    synchronized (queue) {
      if (!queue.newTasksMayBeScheduled) {
        throw new IllegalStateException("Timer already cancelled.");
      }

      /*
       * If the TimerThread has exited without an error
       * it is restarted. See the commentary in TimerThread.run.
       */
      if (thread == null || !thread.isAlive()) {
        thread = new TimerThread(queue);
        thread.start();
      }

      synchronized (task.lock) {
        if (task.state != TimerTask.VIRGIN) {
          throw new IllegalStateException("Task already scheduled or cancelled");
        }
        task.nextExecutionTime = time;
        task.period = period;
        task.state = TimerTask.SCHEDULED;
        task.isUserClock = isUserClock;
      }

      queue.add(task);
      if (queue.getMin() == task) queue.notify();
    }
  }
Example #4
0
 public static void finish(String name) {
   System.out.println(name + ": " + (JVM.monotonicTimeMillis() - start));
 }
Example #5
0
 public static void begin() {
   System.gc();
   start = JVM.monotonicTimeMillis();
 }
Example #6
0
/**
 * A facility for threads to schedule tasks for future execution in a background thread. Tasks may
 * be scheduled for one-time execution, or for repeated execution at regular intervals.
 *
 * <p>Corresponding to each <tt>Timer</tt> object is a single background thread that is used to
 * execute all of the timer's tasks, sequentially. Timer tasks should complete quickly. If a timer
 * task takes excessive time to complete, it "hogs" the timer's task execution thread. This can, in
 * turn, delay the execution of subsequent tasks, which may "bunch up" and execute in rapid
 * succession when (and if) the offending task finally completes.
 *
 * <p>After the last live reference to a <tt>Timer</tt> object goes away <i>and</i> all outstanding
 * tasks have completed execution, the timer's task execution thread terminates gracefully (and
 * becomes subject to garbage collection). However, this can take arbitrarily long to occur. By
 * default, the task execution thread does not run as a <i>daemon thread</i>, so it is capable of
 * keeping an application from terminating. If a caller wants to terminate a timer's task execution
 * thread rapidly, the caller should invoke the timer's <tt>cancel</tt> method.
 *
 * <p>If the timer's task execution thread terminates unexpectedly, for example, because its
 * <tt>stop</tt> method is invoked, any further attempt to schedule a task on the timer will result
 * in an <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt> method had been invoked.
 *
 * <p>This class is thread-safe: multiple threads can share a single <tt>Timer</tt> object without
 * the need for external synchronization.
 *
 * <p>This class does <i>not</i> offer real-time guarantees: it schedules tasks using the
 * <tt>Object.wait(long)</tt> method.
 *
 * <p>Timers function only within a single VM and are cancelled when the VM exits. When the VM is
 * started no timers exist, they are created only by application request.
 *
 * @see TimerTask
 * @see Object#wait(long)
 * @since 1.3
 */
public class Timer {
  /**
   * The timer task queue. This data structure is shared with the timer thread. The timer produces
   * tasks, via its various schedule calls, and the timer thread consumes, executing timer tasks as
   * appropriate, and removing them from the queue when they're obsolete.
   */
  private TaskQueue queue = new TaskQueue();

  /** The timer thread. */
  private TimerThread thread;

  /** Time of this class initialization in the monotonic clock. */
  private static final long monotonicClockOffset = JVM.monotonicTimeMillis();

  /** Time of this class initialization in the user clock. Can change if the user clock changes. */
  private static long userClockOffset = System.currentTimeMillis();

  /**
   * Creates a new timer. The associated thread does <i>not</i> run as a daemon thread, which may
   * prevent an application from terminating.
   *
   * @see Thread
   * @see #cancel()
   */
  public Timer() {}

  /**
   * Schedules the specified task for execution after the specified delay.
   *
   * @param task task to be scheduled.
   * @param delay delay in milliseconds before task is to be executed.
   * @throws IllegalArgumentException if <tt>delay</tt> is negative, or <tt>delay +
   *     System.currentTimeMillis()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, or timer was
   *     cancelled.
   */
  public void schedule(TimerTask task, long delay) {
    if (delay < 0) throw new IllegalArgumentException("Negative delay.");
    if (System.currentTimeMillis() + delay < 0) {
      throw new IllegalArgumentException("Illegal execution time.");
    }
    sched(task, null, delay, 0);
  }

  /**
   * Schedules the specified task for execution at the specified time. If the time is in the past,
   * the task is scheduled for immediate execution.
   *
   * @param task task to be scheduled.
   * @param time time at which task is to be executed.
   * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, timer was cancelled,
   *     or timer thread terminated.
   */
  public void schedule(TimerTask task, Date time) {
    if (time == null) {
      throw new NullPointerException();
    }
    sched(task, time, 0, 0);
  }

  /**
   * Schedules the specified task for repeated <i>fixed-delay execution</i>, beginning after the
   * specified delay. Subsequent executions take place at approximately regular intervals separated
   * by the specified period.
   *
   * <p>In fixed-delay execution, each execution is scheduled relative to the actual execution time
   * of the previous execution. If an execution is delayed for any reason (such as garbage
   * collection or other background activity), subsequent executions will be delayed as well. In the
   * long run, the frequency of execution will generally be slightly lower than the reciprocal of
   * the specified period (assuming the system clock underlying <tt>Object.wait(long)</tt> is
   * accurate).
   *
   * <p>Fixed-delay execution is appropriate for recurring activities that require "smoothness." In
   * other words, it is appropriate for activities where it is more important to keep the frequency
   * accurate in the short run than in the long run. This includes most animation tasks, such as
   * blinking a cursor at regular intervals. It also includes tasks wherein regular activity is
   * performed in response to human input, such as automatically repeating a character as long as a
   * key is held down.
   *
   * @param task task to be scheduled.
   * @param delay delay in milliseconds before task is to be executed.
   * @param period time in milliseconds between successive task executions.
   * @throws IllegalArgumentException if <tt>delay</tt> is negative, or <tt>delay +
   *     System.currentTimeMillis()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, timer was cancelled,
   *     or timer thread terminated.
   */
  public void schedule(TimerTask task, long delay, long period) {
    if (delay < 0) throw new IllegalArgumentException("Negative delay.");
    if (period <= 0) throw new IllegalArgumentException("Non-positive period.");
    if (System.currentTimeMillis() + delay < 0) {
      throw new IllegalArgumentException("Illegal execution time.");
    }
    sched(task, null, delay, -period);
  }

  /**
   * Schedules the specified task for repeated <i>fixed-delay execution</i>, beginning at the
   * specified time. Subsequent executions take place at approximately regular intervals, separated
   * by the specified period.
   *
   * <p>In fixed-delay execution, each execution is scheduled relative to the actual execution time
   * of the previous execution. If an execution is delayed for any reason (such as garbage
   * collection or other background activity), subsequent executions will be delayed as well. In the
   * long run, the frequency of execution will generally be slightly lower than the reciprocal of
   * the specified period (assuming the system clock underlying <tt>Object.wait(long)</tt> is
   * accurate).
   *
   * <p>Fixed-delay execution is appropriate for recurring activities that require "smoothness." In
   * other words, it is appropriate for activities where it is more important to keep the frequency
   * accurate in the short run than in the long run. This includes most animation tasks, such as
   * blinking a cursor at regular intervals. It also includes tasks wherein regular activity is
   * performed in response to human input, such as automatically repeating a character as long as a
   * key is held down.
   *
   * @param task task to be scheduled.
   * @param firstTime First time at which task is to be executed.
   * @param period time in milliseconds between successive task executions.
   * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, timer was cancelled,
   *     or timer thread terminated.
   */
  public void schedule(TimerTask task, Date firstTime, long period) {
    if (period <= 0) throw new IllegalArgumentException("Non-positive period.");
    if (firstTime == null) {
      throw new NullPointerException();
    }
    sched(task, firstTime, 0, -period);
  }

  /**
   * Schedules the specified task for repeated <i>fixed-rate execution</i>, beginning after the
   * specified delay. Subsequent executions take place at approximately regular intervals, separated
   * by the specified period.
   *
   * <p>In fixed-rate execution, each execution is scheduled relative to the scheduled execution
   * time of the initial execution. If an execution is delayed for any reason (such as garbage
   * collection or other background activity), two or more executions will occur in rapid succession
   * to "catch up." In the long run, the frequency of execution will be exactly the reciprocal of
   * the specified period (assuming the system clock underlying <tt>Object.wait(long)</tt> is
   * accurate).
   *
   * <p>Fixed-rate execution is appropriate for recurring activities that are sensitive to
   * <i>absolute</i> time, such as ringing a chime every hour on the hour, or running scheduled
   * maintenance every day at a particular time. It is also appropriate for for recurring activities
   * where the total time to perform a fixed number of executions is important, such as a countdown
   * timer that ticks once every second for ten seconds. Finally, fixed-rate execution is
   * appropriate for scheduling multiple repeating timer tasks that must remain synchronized with
   * respect to one another.
   *
   * @param task task to be scheduled.
   * @param delay delay in milliseconds before task is to be executed.
   * @param period time in milliseconds between successive task executions.
   * @throws IllegalArgumentException if <tt>delay</tt> is negative, or <tt>delay +
   *     System.currentTimeMillis()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, timer was cancelled,
   *     or timer thread terminated.
   */
  public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
    if (delay < 0) throw new IllegalArgumentException("Negative delay.");
    if (period <= 0) throw new IllegalArgumentException("Non-positive period.");
    if (System.currentTimeMillis() + delay < 0) {
      throw new IllegalArgumentException("Illegal execution time.");
    }
    sched(task, null, delay, period);
  }

  /**
   * Schedules the specified task for repeated <i>fixed-rate execution</i>, beginning at the
   * specified time. Subsequent executions take place at approximately regular intervals, separated
   * by the specified period.
   *
   * <p>In fixed-rate execution, each execution is scheduled relative to the scheduled execution
   * time of the initial execution. If an execution is delayed for any reason (such as garbage
   * collection or other background activity), two or more executions will occur in rapid succession
   * to "catch up." In the long run, the frequency of execution will be exactly the reciprocal of
   * the specified period (assuming the system clock underlying <tt>Object.wait(long)</tt> is
   * accurate).
   *
   * <p>Fixed-rate execution is appropriate for recurring activities that are sensitive to
   * <i>absolute</i> time, such as ringing a chime every hour on the hour, or running scheduled
   * maintenance every day at a particular time. It is also appropriate for for recurring activities
   * where the total time to perform a fixed number of executions is important, such as a countdown
   * timer that ticks once every second for ten seconds. Finally, fixed-rate execution is
   * appropriate for scheduling multiple repeating timer tasks that must remain synchronized with
   * respect to one another.
   *
   * @param task task to be scheduled.
   * @param firstTime First time at which task is to be executed.
   * @param period time in milliseconds between successive task executions.
   * @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, timer was cancelled,
   *     or timer thread terminated.
   */
  public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
    if (period <= 0) throw new IllegalArgumentException("Non-positive period.");
    if (firstTime == null) {
      throw new NullPointerException();
    }
    sched(task, firstTime, 0, period);
  }

  /**
   * Schedule the specified timer task for execution at the specified time with the specified
   * period, in milliseconds. If period is positive, the task is scheduled for repeated execution;
   * if period is zero, the task is scheduled for one-time execution. Time is specified in
   * Date.getTime() format. This method checks timer state, task state, and initial execution time,
   * but not period.
   *
   * @param task task to be scheduled.
   * @param userTime the user time at which task is to be executed or <tt>null</tt> if the delay is
   *     specified
   * @param delay the delay in milliseconds before the task execution
   * @param period time in milliseconds between successive task executions.
   * @param isUserClock true if the time is bound to user clock
   * @throws IllegalArgumentException if <tt>time()</tt> is negative.
   * @throws IllegalStateException if task was already scheduled or cancelled, timer was cancelled,
   *     or timer thread terminated.
   */
  private void sched(TimerTask task, Date userTime, long delay, long period) {
    final boolean isUserClock = userTime != null;

    long time;

    if (isUserClock) {
      long t = userTime.getTime();
      if (t < 0) {
        throw new IllegalArgumentException("Illegal execution time.");
      }
      time = Timer.userTimeFromStart(t);
    } else {
      time = Timer.monotonicTimeFromStart(JVM.monotonicTimeMillis() + delay);
    }

    synchronized (queue) {
      if (!queue.newTasksMayBeScheduled) {
        throw new IllegalStateException("Timer already cancelled.");
      }

      /*
       * If the TimerThread has exited without an error
       * it is restarted. See the commentary in TimerThread.run.
       */
      if (thread == null || !thread.isAlive()) {
        thread = new TimerThread(queue);
        thread.start();
      }

      synchronized (task.lock) {
        if (task.state != TimerTask.VIRGIN) {
          throw new IllegalStateException("Task already scheduled or cancelled");
        }
        task.nextExecutionTime = time;
        task.period = period;
        task.state = TimerTask.SCHEDULED;
        task.isUserClock = isUserClock;
      }

      queue.add(task);
      if (queue.getMin() == task) queue.notify();
    }
  }

  /**
   * Terminates this timer, discarding any currently scheduled tasks. Does not interfere with a
   * currently executing task (if it exists). Once a timer has been terminated, its execution thread
   * terminates gracefully, and no more tasks may be scheduled on it.
   *
   * <p>Note that calling this method from within the run method of a timer task that was invoked by
   * this timer absolutely guarantees that the ongoing task execution is the last task execution
   * that will ever be performed by this timer.
   *
   * <p>This method may be called repeatedly; the second and subsequent calls have no effect.
   */
  public void cancel() {
    synchronized (queue) {
      queue.newTasksMayBeScheduled = false;
      queue.clear();
      queue.notify(); // In case queue was already empty.
    }
  }

  private static long monotonicTimeFromStart(long monotonicTime) {
    return monotonicTime - monotonicClockOffset;
  }

  private static long userTimeFromStart(long userTime) {
    return userTime - userClockOffset;
  }

  static long relativeTimeToUserTime(long relativeTime) {
    return relativeTime + userClockOffset;
  }

  static long monotonicTimeMillis() {
    return monotonicTimeFromStart(JVM.monotonicTimeMillis());
  }

  /**
   * The millisecond threshold to signal user clock skew. User clock deviations below the threshold
   * are accumulated and reported only when they exceed the threshold.
   */
  private static final int SKEW_THRESHOLD = 100;

  /**
   * The millisecond period to check for user clock skew. Since many platforms do not notify
   * applications about the user clock change, we periodically check for the skew.
   */
  static final int USER_CLOCK_CHECK_PERIOD = 1000;

  /**
   * Returns the value of the user clock skew in milliseconds. Returned is the deviation of the user
   * clock from the monotonic clock accumulated since the previous invocation of this method in this
   * task. Deviations below the <code>SKEW_THRESHOLD</code> are not reported. They are accumulated
   * until they exceed the threshold.
   *
   * @return the user clock skew
   */
  static long userClockSkew() {
    long newDelta = System.currentTimeMillis() - JVM.monotonicTimeMillis();
    long oldDelta = userClockOffset - monotonicClockOffset;
    long skew = newDelta - oldDelta;
    if (Math.abs(skew) < SKEW_THRESHOLD) {
      skew = 0;
    }

    userClockOffset += skew;
    return skew;
  }
}
Example #7
0
 static long monotonicTimeMillis() {
   return monotonicTimeFromStart(JVM.monotonicTimeMillis());
 }