public void setDone(boolean b) {
    try {
      lock.lock();
      done = b;

      if (!done) cv.signal();
    } finally {
      lock.unlock();
    }
  }
 public void run() {
   try {
     lock.lock();
     while (true) {
       try {
         if (done) {
           cv.await();
         } else {
           nextCharacter();
           cv.await(getPauseTime(), TimeUnit.MILLISECONDS);
         }
       } catch (InterruptedException ie) {
         return;
       }
     }
   } finally {
     lock.unlock();
   }
 }
public class RandomCharacterGenerator extends Thread implements CharacterSource {
  private static char[] chars;
  private static String charArray = "abcdefghijklmnopqrstuvwxyz0123456789";

  static {
    chars = charArray.toCharArray();
  }

  private Random random;
  private CharacterEventHandler handler;
  private boolean done = true;
  private Lock lock = new ReentrantLock();
  private Condition cv = lock.newCondition();

  public RandomCharacterGenerator() {
    random = new Random();
    handler = new CharacterEventHandler();
  }

  public int getPauseTime() {
    return (int) (Math.max(1000, 5000 * random.nextDouble()));
  }

  public void addCharacterListener(CharacterListener cl) {
    handler.addCharacterListener(cl);
  }

  public void removeCharacterListener(CharacterListener cl) {
    handler.removeCharacterListener(cl);
  }

  public void nextCharacter() {
    handler.fireNewCharacter(this, (int) chars[random.nextInt(chars.length)]);
  }

  public void run() {
    try {
      lock.lock();
      while (true) {
        try {
          if (done) {
            cv.await();
          } else {
            nextCharacter();
            cv.await(getPauseTime(), TimeUnit.MILLISECONDS);
          }
        } catch (InterruptedException ie) {
          return;
        }
      }
    } finally {
      lock.unlock();
    }
  }

  public void setDone(boolean b) {
    try {
      lock.lock();
      done = b;

      if (!done) cv.signal();
    } finally {
      lock.unlock();
    }
  }
}