public void shutdown() {
    synchronized (cache) {
      cache.clear();
      curSet.clear();
      urgentImageIds.clear();

      // wake any sleeping threads
      cache.notifyAll();
    }

    loaderPool.shutdown();
  }
  public void imageLoaded(String filePath, GLImage image) {
    synchronized (cache) // because of race with changeWorkingSet() and getGLImage
    {
      int priority = curSet.getPriority(filePath);
      boolean isInCurSet = priority > Integer.MIN_VALUE;

      if (DEBUG) System.out.printf("RamTextureCache: loaded %s (pri=%d)\n", filePath, priority);

      // Store the loaded image in cache
      boolean full = !cache.store(filePath, image, image.nBytes, priority);

      // Stop loading images if the cache is full.
      // Second condition is important in case image was from previous
      // working set - we don't want to abort loading the new set
      if (full && isInCurSet) {
        if (DEBUG) System.out.println("RamTextureCache: cache is full, stop loading");
        loaderPool.clearJobs();
      }

      // wake up threads inside getGLImage()
      cache.notifyAll();
    }
  }