Last active
December 17, 2015 02:49
-
-
Save wsky/5538632 to your computer and use it in GitHub Desktop.
Resetable timer, java timer can not be reused after cancel, delay is difficult
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
// easy timer task, support delay and reset | |
public class ResetableTimer { | |
private boolean running; | |
private Thread boss; | |
private ExecutorService threadPool; | |
private Runnable task; | |
private int period; | |
protected long lastTime; | |
public ResetableTimer(int periodMillisecond) { | |
this(periodMillisecond, null); | |
} | |
public ResetableTimer(int periodMillisecond, Runnable task) { | |
this.period = periodMillisecond; | |
this.delay(0 - this.period); | |
this.setTask(task); | |
this.threadPool = Executors.newSingleThreadExecutor(); | |
} | |
public void setTask(Runnable task) { | |
this.task = task; | |
} | |
public void start() { | |
if (this.boss != null) | |
return; | |
this.running = true; | |
this.boss = new Thread(new Runnable() { | |
@Override | |
public void run() { | |
while (running) { | |
long split = System.currentTimeMillis() - lastTime; | |
if (split >= period && task != null) { | |
try { | |
threadPool.execute(task); | |
} catch (Exception e) { | |
e.printStackTrace(); | |
} | |
delay(); | |
} | |
try { | |
Thread.sleep(split >= period ? period : period - split); | |
} catch (InterruptedException e) { | |
} | |
} | |
} | |
}); | |
this.boss.start(); | |
} | |
public void stop() throws InterruptedException { | |
this.running = false; | |
this.boss.join(); | |
this.boss = null; | |
} | |
public void delay() { | |
this.delay(0); | |
} | |
public void delay(int delayMillisecond) { | |
this.lastTime = System.currentTimeMillis() + delayMillisecond; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import static org.junit.Assert.*; | |
import java.util.concurrent.CountDownLatch; | |
import java.util.concurrent.atomic.AtomicBoolean; | |
import org.junit.Test; | |
public class RestableTimerTest { | |
@Test | |
public void start_test() throws InterruptedException { | |
int c = 5; | |
final CountDownLatch latch = new CountDownLatch(c); | |
final int period = 50; | |
final ResetableTimer timer = new ResetableTimer(period); | |
Runnable task = new Runnable() { | |
@Override | |
public void run() { | |
latch.countDown(); | |
} | |
}; | |
timer.setTask(task); | |
timer.start(); | |
long last = timer.lastTime; | |
latch.await(); | |
assertTrue(System.currentTimeMillis() - last >= period * c); | |
timer.stop(); | |
} | |
@Test | |
public void delay_test() throws InterruptedException { | |
final CountDownLatch latch1 = new CountDownLatch(1); | |
final CountDownLatch latch2 = new CountDownLatch(1); | |
final int period = 100; | |
final ResetableTimer timer = new ResetableTimer(period); | |
final AtomicBoolean atomicBoolean = new AtomicBoolean(true); | |
Runnable task = new Runnable() { | |
@Override | |
public void run() { | |
if (atomicBoolean.getAndSet(false)) | |
latch1.countDown(); | |
else | |
latch2.countDown(); | |
} | |
}; | |
timer.setTask(task); | |
timer.start(); | |
latch1.await(); | |
Thread.sleep(10); | |
long last = timer.lastTime; | |
timer.delay(1000); | |
latch2.await(); | |
assertTrue(System.currentTimeMillis() - last >= 1000); | |
timer.stop(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
stop()方法内可否Interrupt boss线程的Sleep? 因为每次调用stop时要等上几时秒