public void run() { try { if (null == logger) { throw new NullPointerException("must call setLogger"); } logger.info("starting"); monitor(); yield(); } catch (Exception e) { if (e instanceof ExecutionException) { logger.logException("fatal execution error", e.getCause()); } else { logger.logException("fatal error", e); } // stop the world System.exit(-1); } finally { pool.shutdownNow(); running = false; logger.info( "exiting after " + timer.getEventCount() + "/" + taskCount + ", " + timer.getProgressMessage()); } }
/** @throws ExecutionException */ protected void monitor() throws ExecutionException { int displayMillis = DISPLAY_MILLIS; int futureMillis = FUTURE_MILLIS; int sleepMillis = SLEEP_MILLIS; Future<TimedEvent[]> future = null; /* Initialize lastFutureMillis so that we do not get * warnings on slow queue startup. */ long currentMillis = System.currentTimeMillis(); long lastDisplayMillis = 0; long lastFutureMillis = currentMillis; TimedEvent[] lastEvent = null; logger.finest( "looping every " + sleepMillis + ", core=" + pool.getCorePoolSize() + ", active=" + pool.getActiveCount() + ", tasks=" + taskCount); timer = new Timer(); // run until all futures have been checked do { // try to avoid thread starvation yield(); // check completed tasks // sometimes this goes so fast that we never leave the loop, // so progress is never displayed... so limit the number of loops. do { try { future = completionService.poll(SLEEP_MILLIS, TimeUnit.MILLISECONDS); if (null != future) { // record result, or throw exception lastFutureMillis = System.currentTimeMillis(); try { lastEvent = future.get(); if (null == lastEvent) { throw new FatalException("unexpected null event"); } for (int i = 0; i < lastEvent.length; i++) { // discard events to reduce memory utilization if (null != lastEvent[i]) { timer.add(lastEvent[i], false); } } } catch (ExecutionException e) { if (fatalErrors) { throw e; } Throwable cause = e.getCause(); if (null != cause && cause instanceof FatalException) { throw (FatalException) cause; } logger.logException("non-fatal", e); timer.incrementEventCount(false); } } } catch (InterruptedException e) { // reset interrupt status and continue Thread.interrupted(); logger.logException("interrupted in poll() or get()", e); continue; } currentMillis = System.currentTimeMillis(); if (currentMillis - lastDisplayMillis > displayMillis) { lastDisplayMillis = currentMillis; logger.finer( "thread count: core=" + pool.getCorePoolSize() + ", active=" + pool.getActiveCount() + ", tasks=" + taskCount); if (null != lastEvent) { logger.info( "" + timer.getEventCount() + "/" + taskCount + ", " + timer.getProgressMessage(false) + ", " + lastEvent[0].getDescription()); if (config.doPrintCurrRate()) { String currMsg = timer.getCurrProgressMessage(); if (currMsg != null) logger.info(currMsg); } } } } while (null != future); logger.finer( "running = " + running + ", terminated = " + pool.isTerminated() + ", last future = " + lastFutureMillis); // currentMillis has already been set recently if (currentMillis - lastFutureMillis > futureMillis) { logger.warning("no futures received in over " + futureMillis + " ms"); break; } } while (running && !pool.isTerminated()); // NB - caller will set running to false to ensure exit }