java 时间轮算法_时间轮算法实现

TimingWheel.java

private final long tickDuration;

private final int ticksPerWheel;

private volatile int currentTickIndex = 0;

private final List> expirationListeners = Collections.synchronizedList(Lists.newArrayList());

private final ArrayList> wheel;

private final Map> indicator = new ConcurrentHashMap<>();

private final AtomicBoolean shutdown = new AtomicBoolean(false);

private final ReadWriteLock lock = new ReentrantReadWriteLock();

private Thread workerThread;

public TimingWheel(int tickDuration, int ticksPerWheel, TimeUnit timeUnit) {

if (timeUnit == null) {

throw new NullPointerException("unit");

}

if (tickDuration <= 0) {

throw new IllegalArgumentException("tickDuration must be greater than 0: " + tickDuration);

}

if (ticksPerWheel <= 0) {

throw new IllegalArgumentException("ticksPerWheel must be greater than 0: " + ticksPerWheel);

}

this.wheel = new ArrayList<>();

this.tickDuration = TimeUnit.MILLISECONDS.convert(tickDuration, timeUnit);

this.ticksPerWheel = ticksPerWheel + 1;

for (int i = 0; i < this.ticksPerWheel; i++) {

wheel.add(new Slot<>(i));

}

wheel.trimToSize();

workerThread = new Thread(new TickWorker(), "Timing-Wheel");

}

public void start() {

if (shutdown.get()) {

throw new IllegalStateException("Cannot be started once stopped");

}

if (!workerThread.isAlive()) {

workerThread.start();

}

}

public boolean stop() {

if (!shutdown.compareAndSet(false, true)) {

return false;

}

boolean interrupted = false;

while (workerThread.isAlive()) {

workerThread.interrupt();

try {

workerThread.join(100);

} catch (InterruptedException e) {

interrupted = true;

}

}

if (interrupted) {

Thread.currentThread().interrupt();

}

return true;

}

public void addExpirationListener(ExpirationListener listener) {

expirationListeners.add(listener);

}

public void removeExpirationListener(ExpirationListener listener) {

expirationListeners.remove(listener);

}

public long add(E e) {

synchronized (e) {

checkAdd(e);

int previousTickIndex = getPreviousTickIndex();

Slot slot = wheel.get(previousTickIndex);

slot.add(e);

indicator.put(e, slot);

return (ticksPerWheel - 1) * tickDuration;

}

}

private void checkAdd(E e) {

Slot slot = indicator.get(e);

if (slot != null) {

slot.remove(e);

}

}

private int getPreviousTickIndex() {

lock.readLock().lock();

try {

int cti = currentTickIndex;

if (cti == 0) {

return ticksPerWheel - 1;

}

return cti - 1;

} finally {

lock.readLock().unlock();

}

}

public boolean remove(E e) {

synchronized (e) {

Slot slot = indicator.get(e);

if (slot == null) {

return false;

}

indicator.remove(e);

return slot.remove(e) != null;

}

}

private void notifyExpired(int idx) {

Slot slot = wheel.get(idx);

Set elements = slot.elements();

for (E e : elements) {

slot.remove(e);

synchronized (e) {

Slot latestSlot = indicator.get(e);

if (latestSlot.equals(slot)) {

indicator.remove(e);

}

}

for (ExpirationListener listener : expirationListeners) {

listener.expired(e);

}

}

}

private class TickWorker implements Runnable {

private long startTime;

private long tick;

@Override

public void run() {

startTime = System.currentTimeMillis();

tick = 1;

for (int i = 0; !shutdown.get(); i++) {

if (i == wheel.size()) {

i = 0;

}

lock.writeLock().lock();

try {

currentTickIndex = i;

} finally {

lock.writeLock().unlock();

}

notifyExpired(currentTickIndex);

waitForNextTick();

System.out.println("tick: " + tick);

}

}

private void waitForNextTick() {

for (; ; ) {

long currentTime = System.currentTimeMillis();

long sleepTime = tickDuration * tick - (currentTime - startTime);

if (sleepTime <= 0) {

break;

}

try {

Thread.sleep(sleepTime);

} catch (InterruptedException e) {

return;

}

}

tick++;

}

}

private static class Slot {

private int id;

private Map elements = new ConcurrentHashMap<>();

public Slot(int id) {

this.id = id;

}

public void add(E e) {

elements.put(e, e);

}

public E remove(E e) {

return elements.remove(e);

}

public Set elements() {

return elements.keySet();

}

@Override

public int hashCode() {

final int prime = 31;

int result = 1;

result = prime * result + id;

return result;

}

@Override

public boolean equals(Object obj) {

if (this == obj) {

return true;

}

if (obj == null) {

return false;

}

if (getClass() != obj.getClass()) {

return false;

}

@SuppressWarnings("rawtypes")

Slot other = (Slot) obj;

return id == other.id;

}

@Override

public String toString() {

return "Slot [id=" + id + ", elements=" + elements + "]";

}

}

ExpirationListener

void expired(E expiredObject);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值