Skip to content

Instantly share code, notes, and snippets.

@wsky
Last active December 17, 2015 02:49
Show Gist options
  • Select an option

  • Save wsky/5538632 to your computer and use it in GitHub Desktop.

Select an option

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
Copy Markdown

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