Skip to content

Instantly share code, notes, and snippets.

@wsky
Last active December 17, 2015 02:49
Show Gist options
  • Save wsky/5538632 to your computer and use it in GitHub Desktop.
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
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;
}
}
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();
}
}
@0xbillw
Copy link

0xbillw commented Oct 14, 2014

stop()方法内可否Interrupt boss线程的Sleep? 因为每次调用stop时要等上几时秒

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment