@Override
	public void run() {
		logger.log(Level.INFO, "Ticker started.");
		synchronized (syncObject) {
			while (running) {
				if (executionTimes.isEmpty()) {
					logger.log(Level.INFO, "Ticker is waiting for events.");
					try {
						syncObject.wait();
					} catch (InterruptedException ie1) {
						/*
						 * ignore, ticker will land here again if there's
						 * nothing to do.
						 */
					}
				} else {
					EventIdentifier eventIdentifier = executionTimes.peek();
					if (eventIdentifier == null) {
						continue;
					}
					long now = System.currentTimeMillis();
					long executionTime = eventIdentifier.getExecutionTime();
					if (executionTime > now) {
						logger.log(Level.INFO, "Ticker is waiting up to " + (executionTime - now) + " for " + eventIdentifier.getEventName() + " to execute at " + executionTime + ".");
						try {
							syncObject.wait(executionTime - now);
						} catch (InterruptedException ie1) {
							/*
							 * ignore, ticker will land here again if there's
							 * nothing to do.
							 */
						}
					} else {
						removeEventIdentifier(eventIdentifier);
						Runnable runnable = runnables.remove(eventIdentifier);
						if (runnable != null) {
							logger.log(Level.INFO, "Ticker executes " + eventIdentifier.getEventName() + ", " + (now - executionTime) + " ms late");
							Thread eventThread = threadFactory.newThread(runnable);
							eventThread.setName("Event Thread for " + eventIdentifier.getEventName() + " @ " + executionTime);
							eventThread.start();
						}
					}
				}
			}
		}
	}