public void register(PeerControlInstance instance) {
    instanceWrapper wrapper = new instanceWrapper(instance);

    wrapper.setNextTick(latest_time + random.nextInt(SCHEDULE_PERIOD_MILLIS));

    try {
      this_mon.enter();

      Map<PeerControlInstance, instanceWrapper> new_map =
          new HashMap<PeerControlInstance, instanceWrapper>(instance_map);

      new_map.put(instance, wrapper);

      instance_map = new_map;

      pending_registrations.add(wrapper);

      registrations_changed = true;

    } finally {

      this_mon.exit();
    }
  }
  protected void schedule() {
    SystemTime.registerMonotonousConsumer(
        new SystemTime.TickConsumer() {
          public void consume(long time) {
            synchronized (PeerControlSchedulerBasic.this) {
              PeerControlSchedulerBasic.this.notify();
            }
          }
        });

    List<instanceWrapper> instances = new LinkedList<instanceWrapper>();

    long tick_count = 0;
    long last_stats_time = SystemTime.getMonotonousTime();

    while (true) {

      if (registrations_changed) {

        try {
          this_mon.enter();

          Iterator<instanceWrapper> it = instances.iterator();

          while (it.hasNext()) {

            if (it.next().isUnregistered()) {

              it.remove();
            }
          }

          for (int i = 0; i < pending_registrations.size(); i++) {

            instances.add(pending_registrations.get(i));
          }

          pending_registrations.clear();

          registrations_changed = false;

        } finally {

          this_mon.exit();
        }
      }

      latest_time = SystemTime.getMonotonousTime();

      long current_schedule_count = schedule_count;

      for (instanceWrapper inst : instances) {

        long target = inst.getNextTick();

        long diff = latest_time - target;

        if (diff >= 0) {

          tick_count++;

          inst.schedule(latest_time);

          schedule_count++;

          long new_target = target + SCHEDULE_PERIOD_MILLIS;

          if (new_target <= latest_time) {

            new_target = latest_time + (target % SCHEDULE_PERIOD_MILLIS);
          }

          inst.setNextTick(new_target);
        }
      }

      synchronized (this) {
        if (current_schedule_count == schedule_count) {

          wait_count++;

          try {
            long wait_start = SystemTime.getHighPrecisionCounter();

            wait(SCHEDULE_PERIOD_MILLIS);

            long wait_time = SystemTime.getHighPrecisionCounter() - wait_start;

            total_wait_time += wait_time;

          } catch (Throwable e) {

            Debug.printStackTrace(e);
          }

        } else {

          yield_count++;

          Thread.yield();
        }
      }

      long stats_diff = latest_time - last_stats_time;

      if (stats_diff > 10000) {

        // System.out.println( "stats: time = " + stats_diff + ", ticks = " + tick_count + ", inst =
        // " + instances.size());

        last_stats_time = latest_time;

        tick_count = 0;
      }
    }
  }