Java 定时器优化

本文将介绍如何使用 Java 8 的 Optional 类、Lambda 表达式、ConcurrentHashMap 和 优化 tryCancel 方法来优化 Java 定时器代码,使其更加简洁、安全且高效。

代码优化

以下是优化后的代码:javaimport com.taobao.hsf.NamedThreadFactory;import com.taobao.powermsg3.sdk.localserver.PmLocalServerSDKConfig;import io.netty.util.HashedWheelTimer;import io.netty.util.Timeout;import io.netty.util.TimerTask;import io.vertx.core.Context;import lombok.extern.slf4j.Slf4j;import org.apache.commons.collections4.CollectionUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;import javax.annotation.PreDestroy;import java.time.Duration;import java.util.Objects;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicLong;

@Component@Slf4jpublic class Scheduler { private final HashedWheelTimer hashedWheelTimer;

private final AtomicLong timerIdGen = new AtomicLong();

private final ConcurrentHashMap<Long, Timeout> timerId2Timeout = new ConcurrentHashMap<>();    private final ConcurrentHashMap<Object, Timeout> timerKey2Timeouts = new ConcurrentHashMap<>();

@Autowired    public Scheduler(final PmLocalServerSDKConfig pmLocalServerSDKConfig) {        final PmLocalServerSDKConfig.SchedulerConfig schedulerConfig = pmLocalServerSDKConfig.getScheduler();        final int tickInMillis = Math.max(1, schedulerConfig.getTickDurationInMillis());        final int ticksPerWheel = Math.max(512, schedulerConfig.getTicksPerWheel());        this.hashedWheelTimer = new HashedWheelTimer(                new NamedThreadFactory('localserver-scheduler'),                tickInMillis, TimeUnit.MILLISECONDS,                ticksPerWheel        );    }

public boolean cancel(final Long timerId) {        final Timeout timeout = timerId2Timeout.remove(timerId);        if (timeout != null) {            timeout.cancel();            return true;        }        return false;    }

public boolean cancel(final Object timerKey) {        final Timeout timeout = timerKey2Timeouts.remove(timerKey);        if (timeout != null) {            timeout.cancel();            return true;        }        return false;    }

public Long scheduleOnce(final Duration delay,                             final Runnable runnable,                             final Context context) {        Objects.requireNonNull(delay, 'delay should not be null.');        Objects.requireNonNull(runnable, 'runnable should not be null.');        Objects.requireNonNull(context, 'context should not be null.');        final Long timerId = timerIdGen.incrementAndGet();        timerId2Timeout.compute(timerId, (key, timeout) ->                hashedWheelTimer.newTimeout(t -> {                    Optional.ofNullable(timerId2Timeout.remove(timerId)).ifPresent(Timeout::cancel);                    context.runOnContext(event -> {                        runnable.run();                    });                }, delay.toNanos(), TimeUnit.NANOSECONDS));        return timerId;    }

public void scheduleOnce(final Object timerKey,                             final Duration delay,                             final Runnable runnable,                             final Context context) {        Objects.requireNonNull(timerKey, 'timerKey should not be null.');        Objects.requireNonNull(delay, 'delay should not be null.');        Objects.requireNonNull(runnable, 'runnable should not be null.');        Objects.requireNonNull(context, 'context should not be null.');        timerKey2Timeouts.computeIfAbsent(                timerKey,                (key) -> hashedWheelTimer.newTimeout(t -> {                    context.runOnContext(event -> {                        timerKey2Timeouts.remove(timerKey);                        runnable.run();                    });                }, delay.toNanos(), TimeUnit.NANOSECONDS)        );    }

public Long scheduleWithFixDelay(final Duration initialDelay,                                     final Duration delay,                                     final Runnable runnable,                                     final Context context) {        Objects.requireNonNull(initialDelay, 'initialDelay should not be null.');        Objects.requireNonNull(delay, 'delay should not be null.');        Objects.requireNonNull(runnable, 'runnable should not be null.');        Objects.requireNonNull(context, 'context should not be null.');        final Long timerId = timerIdGen.incrementAndGet();        final Runnable scheduledRunnable = new Runnable() {            final Runnable self = this;

        @Override            public void run() {                try {                    runnable.run();                } catch (Exception e) {                    log.error('Error when trigger task of runnable:[{}]', runnable, e);                } finally {                    timerId2Timeout.computeIfPresent(timerId, (key, timeout) -> {                        tryCancel(timeout);                        return scheduleWithTimerId(delay, self, context);                    });                }            }        };        timerId2Timeout.compute(timerId, (key, timeout) ->                scheduleWithTimerId(initialDelay, scheduledRunnable, context));        return timerId;    }

public void scheduleWithFixDelay(final Object timerKey,                                     final Duration initialDelay,                                     final Duration delay,                                     final Runnable runnable,                                     final Context context) {        Objects.requireNonNull(timerKey, 'timerKey should not be null.');        Objects.requireNonNull(initialDelay, 'initialDelay should not be null.');        Objects.requireNonNull(delay, 'delay should not be null.');        Objects.requireNonNull(runnable, 'runnable should not be null.');        Objects.requireNonNull(context, 'context should not be null.');        final Runnable scheduledRunnable = new Runnable() {            final Runnable self = this;

        @Override            public void run() {                try {                    runnable.run();                } catch (Exception e) {                    log.error('Error when trigger task of runnable:[{}]', runnable, e);                } finally {                    timerKey2Timeouts.computeIfPresent(                            timerKey,                            (key, timeout) -> {                                tryCancel(timeout);                                return scheduleWithTimerKey(delay, self, context);                            });                }            }        };

    timerKey2Timeouts.computeIfAbsent(timerKey, (key) -> scheduleWithTimerKey(initialDelay, scheduledRunnable, context));    }

private boolean tryCancel(final Timeout timeout) {        if (timeout != null) {            return timeout.cancel();        }        return true;    }

private Timeout scheduleWithTimerId(final Duration delay,                                        final Runnable runnable,                                        final Context context) {        return hashedWheelTimer.newTimeout(                t -> context.runOnContext(event -> runnable.run()),                delay.toNanos(),                TimeUnit.NANOSECONDS);    }

private Timeout scheduleWithTimerKey(final Duration delay,                                         final Runnable runnable,                                         final Context context) {        return hashedWheelTimer.newTimeout(                t -> context.runOnContext(event -> runnable.run()),                delay.toNanos(),                TimeUnit.NANOSECONDS);    }

@PostConstruct    protected void init() {        hashedWheelTimer.start();    }

@PreDestroy    protected void stop() {        final Set<Timeout> timeouts = hashedWheelTimer.stop();        if (CollectionUtils.isNotEmpty(timeouts)) {            for (Timeout timeout : timeouts) {                if (timeout.isCancelled() || timeout.isExpired()) {                    continue;                }                final TimerTask task = timeout.task();                try {                    task.run(timeout);                } catch (Exception e) {                    //Ignore                }            }        }
Java 定时器优化:使用 Optional、Lambda 表达式、ConcurrentHashMap 和 优化 tryCancel 方法

原文地址: https://www.cveoy.top/t/topic/lH45 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录