108bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann/* 208bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * Copyright (c) 2017 Mockito contributors 308bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann * This program is made available under the terms of the MIT License. 408bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann */ 52637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinpackage org.mockitousage.verification; 62637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 72637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static java.lang.System.currentTimeMillis; 82637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static java.lang.Thread.MAX_PRIORITY; 92637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static java.util.concurrent.Executors.newScheduledThreadPool; 102637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static java.util.concurrent.TimeUnit.SECONDS; 112637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport static java.util.concurrent.locks.LockSupport.parkUntil; 122637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 132637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.util.concurrent.ScheduledExecutorService; 142637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.util.concurrent.ThreadFactory; 152637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinimport java.util.concurrent.TimeUnit; 162637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 172637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffinclass DelayedExecution { 182637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin private static final int CORE_POOL_SIZE = 3; 192637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin /** 202637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * Defines the number of milliseconds we expecting a Thread might need to unpark, we use this to avoid "oversleeping" while awaiting the deadline for 212637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin */ 222637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin private static final long MAX_EXPECTED_OVERSLEEP_MILLIS = 50; 232637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 242637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin private final ScheduledExecutorService executor; 252637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 262637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin public DelayedExecution() { 272637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin this.executor = newScheduledThreadPool(CORE_POOL_SIZE, maxPrioThreadFactory()); 282637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 292637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 302637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin public void callAsync(long delay, TimeUnit timeUnit, Runnable r) { 312637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin long deadline = timeUnit.toMillis(delay) + currentTimeMillis(); 322637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 332637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin executor.submit(delayedExecution(r, deadline)); 342637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 352637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 362637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin public void close() throws InterruptedException { 372637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin executor.shutdownNow(); 382637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 392637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin if (!executor.awaitTermination(5, SECONDS)) { 4008bd32ce48b12ae751dd5c4829ff09a6fb9894f0Philip P. Moltmann throw new IllegalStateException("This delayed execution did not terminated after 5 seconds"); 412637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 422637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 432637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 442637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin private static Runnable delayedExecution(final Runnable r, final long deadline) { 452637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin return new Runnable() { 462637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin @Override 472637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin public void run() { 482637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin //we park the current Thread till 50ms before we want to execute the runnable 492637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin parkUntil(deadline - MAX_EXPECTED_OVERSLEEP_MILLIS); 502637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin //now we closing to the deadline by burning CPU-time in a loop 512637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin burnRemaining(deadline); 522637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 532637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin System.out.println("[DelayedExecution] exec delay = "+(currentTimeMillis() - deadline)+"ms"); 542637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 552637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin r.run(); 562637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 572637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 582637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin /** 592637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * Loop in tight cycles until we reach the dead line. We do this cause sleep or park is very not precise, 602637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin * this can causes a Thread to under- or oversleep, sometimes by +50ms. 612637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin */ 622637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin private void burnRemaining(final long deadline) { 632637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin long remaining; 642637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin do { 652637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin remaining = deadline - currentTimeMillis(); 662637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } while (remaining > 0); 672637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 682637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin }; 692637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 702637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin 712637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin private static ThreadFactory maxPrioThreadFactory() { 722637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin return new ThreadFactory() { 732637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin @Override 742637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin public Thread newThread(Runnable r) { 752637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin Thread t = new Thread(r); 762637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin t.setDaemon(true); // allows the JVM to exit when clients forget to call DelayedExecution.close() 772637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin t.setPriority(MAX_PRIORITY); 782637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin return t; 792637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 802637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin }; 812637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin } 822637d96c202372854a7c71466ddcc6e90fc4fc53Paul Duffin} 83