Created
July 8, 2011 07:41
-
-
Save jskorpan/1071323 to your computer and use it in GitHub Desktop.
A ConcurrentSkipListSet based Timer compatible with Netty's HashedWheelTimer
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 org.jboss.netty.util.ThreadRenamingRunnable; | |
| import org.jboss.netty.util.Timeout; | |
| import org.jboss.netty.util.Timer; | |
| import org.jboss.netty.util.TimerTask; | |
| import java.util.Comparator; | |
| import java.util.Iterator; | |
| import java.util.Set; | |
| import java.util.SortedSet; | |
| import java.util.concurrent.ConcurrentSkipListSet; | |
| import java.util.concurrent.TimeUnit; | |
| import java.util.concurrent.atomic.AtomicBoolean; | |
| import java.util.concurrent.atomic.AtomicInteger; | |
| public class SortListTimer implements Timer, Runnable | |
| { | |
| private final SortedSet<InternalTimeout> timeouts = new ConcurrentSkipListSet<InternalTimeout>(new Comparator<InternalTimeout>() { | |
| public int compare(InternalTimeout o1, InternalTimeout o2) | |
| { | |
| return (int) (o1.getExpireTick() - o2.getExpireTick()); | |
| } | |
| }); | |
| private final int resolutionMSEC; | |
| private boolean isRunning; | |
| private Thread timerThread; | |
| private class InternalTimeout implements Timeout | |
| { | |
| private AtomicBoolean isExpired = new AtomicBoolean(); | |
| private AtomicBoolean isCancelled = new AtomicBoolean(); | |
| private long expireTime; | |
| private TimerTask task; | |
| private InternalTimeout(long expireTime, TimerTask task) | |
| { | |
| this.expireTime = expireTime; | |
| this.task = task; | |
| } | |
| public Timer getTimer() | |
| { | |
| return SortListTimer.this; | |
| } | |
| public TimerTask getTask() | |
| { | |
| return task; | |
| } | |
| public boolean isExpired() | |
| { | |
| return isExpired.get(); | |
| } | |
| public boolean isCancelled() | |
| { | |
| return isCancelled.get(); | |
| } | |
| public void cancel() | |
| { | |
| isCancelled.set(true); | |
| } | |
| public long getExpireTick() | |
| { | |
| return expireTime; | |
| } | |
| public void setExpired(boolean b) | |
| { | |
| isExpired.set(b); | |
| } | |
| public void incExpireTime() | |
| { | |
| expireTime ++; | |
| } | |
| } | |
| public SortListTimer(int resolutionMSEC) | |
| { | |
| this.resolutionMSEC = resolutionMSEC; | |
| this.isRunning = true; | |
| this.timerThread = new Thread(new ThreadRenamingRunnable(this, "SortListTimer")); | |
| timerThread.start(); | |
| } | |
| private long getTime() | |
| { | |
| return System.currentTimeMillis(); | |
| } | |
| public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) | |
| { | |
| long expire = getTime() + TimeUnit.MILLISECONDS.convert(delay, unit); | |
| InternalTimeout e = new InternalTimeout(expire, task); | |
| while(!timeouts.add(e)) | |
| { | |
| e.incExpireTime(); | |
| } | |
| return e; | |
| } | |
| public Set<Timeout> stop() | |
| { | |
| isRunning = false; | |
| try | |
| { | |
| timerThread.join(); | |
| } catch (InterruptedException e) | |
| { | |
| } | |
| return null; | |
| } | |
| private void update() | |
| { | |
| long now = getTime(); | |
| Iterator<InternalTimeout> iterator = timeouts.iterator(); | |
| while (iterator.hasNext()) | |
| { | |
| InternalTimeout next = iterator.next(); | |
| if (now > next.getExpireTick()) | |
| { | |
| iterator.remove(); | |
| if (next.isCancelled()) | |
| { | |
| continue; | |
| } | |
| try | |
| { | |
| next.setExpired(true); | |
| next.getTask().run(next); | |
| } catch (Throwable e) | |
| { | |
| e.printStackTrace(); | |
| } | |
| } | |
| else | |
| { | |
| break; | |
| } | |
| } | |
| } | |
| public void run() | |
| { | |
| while (isRunning) | |
| { | |
| update(); | |
| try | |
| { | |
| Thread.sleep(resolutionMSEC); | |
| } catch (InterruptedException e) | |
| { | |
| } | |
| } | |
| } | |
| } |
Author
Well first of all it's working and doesn't skip scheduled events as Netty's
HashedWheelTimer did back in 2011 (
http://lists.jboss.org/pipermail/netty-users/2011-July/004660.html)
With regards to performance we're using it in production under "normal
circumstances".
I suggest you load test it according to your specific use case. A possible
performance hot spot is if many tasks are scheduled at the exact same
timestamp, check out the while-loop in public Timeout newTimeout(TimerTask
task, long delay, TimeUnit unit)
Unless you're doing something very intensive I wouldn't worry.
//JT
Den 13 februari 2012 08:26 skrev Benoit Sigoure <
reply@reply.github.com
:
How does this perform compared to Netty's HashedWheelTimer?
---
Reply to this email directly or view it on GitHub:
https://gist.github.com/1071323
##
##
Jonas Trnstrm
Product Manager
e-mail: jonas.tarnstrom@esn.me
skype: full name "Jonas Trnstrm"
phone: +46 (0)734 231 552
ESN Social Software AB
www.esn.me
Thanks for the quick reply!
Well first of all it's working and doesn't skip scheduled events as Netty's
HashedWheelTimer did back in 2011
Do you know if this bug has been fixed?
With regards to performance we're using it in production under "normal
circumstances".
Can you share how many timer insertions / removal do you typically do per second?
I suggest you load test it according to your specific use case. A possible
performance hot spot is if many tasks are scheduled at the exact same timestamp
Yeah but HashedWheelTimer would have the same hot spot.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How does this perform compared to Netty's
HashedWheelTimer?