@Test public void testTimeMillis() throws Throwable { final AtomicLong slewStart = new AtomicLong(); final AtomicLong offset = new AtomicLong(0); final List<Throwable> errors = Collections.synchronizedList(new ArrayList<Throwable>()); TimeProviderLoader.setTimeProvider(new SlewClock.TimeProvider() { public long currentTimeMillis() { return System.currentTimeMillis() - offset.get(); } }); final AtomicBoolean stopped = new AtomicBoolean(false); final AtomicInteger catchingUp = new AtomicInteger(); SlewClockVerifierThread[] threads = new SlewClockVerifierThread[THREADS]; for(int i =0; i < THREADS; i++) { threads[i] = new SlewClockVerifierThread(stopped, catchingUp, errors, slewStart, i == 0); } for (Thread thread : threads) { thread.start(); } Thread.sleep(TimeUnit.SECONDS.toMillis(DURATION)); System.out.println("Going back in time by " + BACK_IN_TIME); slewStart.set(System.currentTimeMillis()); offset.set(BACK_IN_TIME); Thread.sleep(SLOWRUN ? BACK_IN_TIME * 3 : BACK_IN_TIME * 2); stopped.set(true); for (SlewClockVerifierThread thread : threads) { thread.join(); } if(!errors.isEmpty()) { System.err.println("We have " + errors.size() + " error(s) here!"); throw errors.get(0); } assertThat(catchingUp.get(), is(THREADS)); }
static long timeMillis() { boolean interrupted = false; try { while (true) { long mono = CURRENT.get(); long wall = getCurrentTime(); if (wall == mono) { OFFSET.remove(); return wall; } else if (wall >= mono) { if (CURRENT.compareAndSet(mono, wall)) { OFFSET.remove(); return wall; } } else { long delta = mono - wall; if (delta < DRIFT_MAXIMAL) { OFFSET.remove(); return mono; } else { Long lastDelta = OFFSET.get(); if (lastDelta == null || delta < lastDelta) { long update = wall - delta; update = update < mono ? mono + 1 : update; if (CURRENT.compareAndSet(mono, update)) { OFFSET.set(Long.valueOf(delta)); return update; } } else { try { Thread.sleep(sleepTime(delta, lastDelta)); } catch (InterruptedException e) { interrupted = true; } } } } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } }
SlewClock { static long timeMillis() { boolean interrupted = false; try { while (true) { long mono = CURRENT.get(); long wall = getCurrentTime(); if (wall == mono) { OFFSET.remove(); return wall; } else if (wall >= mono) { if (CURRENT.compareAndSet(mono, wall)) { OFFSET.remove(); return wall; } } else { long delta = mono - wall; if (delta < DRIFT_MAXIMAL) { OFFSET.remove(); return mono; } else { Long lastDelta = OFFSET.get(); if (lastDelta == null || delta < lastDelta) { long update = wall - delta; update = update < mono ? mono + 1 : update; if (CURRENT.compareAndSet(mono, update)) { OFFSET.set(Long.valueOf(delta)); return update; } } else { try { Thread.sleep(sleepTime(delta, lastDelta)); } catch (InterruptedException e) { interrupted = true; } } } } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } }
SlewClock { static long timeMillis() { boolean interrupted = false; try { while (true) { long mono = CURRENT.get(); long wall = getCurrentTime(); if (wall == mono) { OFFSET.remove(); return wall; } else if (wall >= mono) { if (CURRENT.compareAndSet(mono, wall)) { OFFSET.remove(); return wall; } } else { long delta = mono - wall; if (delta < DRIFT_MAXIMAL) { OFFSET.remove(); return mono; } else { Long lastDelta = OFFSET.get(); if (lastDelta == null || delta < lastDelta) { long update = wall - delta; update = update < mono ? mono + 1 : update; if (CURRENT.compareAndSet(mono, update)) { OFFSET.set(Long.valueOf(delta)); return update; } } else { try { Thread.sleep(sleepTime(delta, lastDelta)); } catch (InterruptedException e) { interrupted = true; } } } } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } private  SlewClock(); }
SlewClock { static long timeMillis() { boolean interrupted = false; try { while (true) { long mono = CURRENT.get(); long wall = getCurrentTime(); if (wall == mono) { OFFSET.remove(); return wall; } else if (wall >= mono) { if (CURRENT.compareAndSet(mono, wall)) { OFFSET.remove(); return wall; } } else { long delta = mono - wall; if (delta < DRIFT_MAXIMAL) { OFFSET.remove(); return mono; } else { Long lastDelta = OFFSET.get(); if (lastDelta == null || delta < lastDelta) { long update = wall - delta; update = update < mono ? mono + 1 : update; if (CURRENT.compareAndSet(mono, update)) { OFFSET.set(Long.valueOf(delta)); return update; } } else { try { Thread.sleep(sleepTime(delta, lastDelta)); } catch (InterruptedException e) { interrupted = true; } } } } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } private  SlewClock();  }
SlewClock { static long timeMillis() { boolean interrupted = false; try { while (true) { long mono = CURRENT.get(); long wall = getCurrentTime(); if (wall == mono) { OFFSET.remove(); return wall; } else if (wall >= mono) { if (CURRENT.compareAndSet(mono, wall)) { OFFSET.remove(); return wall; } } else { long delta = mono - wall; if (delta < DRIFT_MAXIMAL) { OFFSET.remove(); return mono; } else { Long lastDelta = OFFSET.get(); if (lastDelta == null || delta < lastDelta) { long update = wall - delta; update = update < mono ? mono + 1 : update; if (CURRENT.compareAndSet(mono, update)) { OFFSET.set(Long.valueOf(delta)); return update; } } else { try { Thread.sleep(sleepTime(delta, lastDelta)); } catch (InterruptedException e) { interrupted = true; } } } } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } private  SlewClock();   }