Repository: apache/dubbo
File: dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/exchange/support/header/AbstractTimerTask.java (Java)

Code before:

    private volatile Timeout timeout;

    AbstractTimerTask(ChannelProvider channelProvider, HashedWheelTimer hashedWheelTimer, Long tick) {
        if (channelProvider == null || hashedWheelTimer == null || tick == null) {
            throw new IllegalArgumentException();
        }
        this.channelProvider = channelProvider;
        this.hashedWheelTimer = hashedWheelTimer;
        this.tick = tick;
        // do not start here because inheritor should set additional timeout parameters before doing task.
    }

    static Long lastRead(Channel channel) {
        return (Long) channel.getAttribute(HeartbeatHandler.KEY_READ_TIMESTAMP);
    }

    static Long lastWrite(Channel channel) {
        return (Long) channel.getAttribute(HeartbeatHandler.KEY_WRITE_TIMESTAMP);
    }

    static Long now() {
        return System.currentTimeMillis();
    }

    public void start() {
        this.timeout = hashedWheelTimer.newTimeout(this, tick, TimeUnit.MILLISECONDS);
    }

    public synchronized void cancel() {
        this.cancel = true;
        this.timeout.cancel();
    }

    private synchronized void reput(Timeout timeout) {
        if (timeout == null) {
            throw new IllegalArgumentException();
        }

        if (cancel) {
            return;
        }

        if (hashedWheelTimer.isStop() || timeout.isCancelled()) {
            return;
        }

        this.timeout = hashedWheelTimer.newTimeout(timeout.task(), tick, TimeUnit.MILLISECONDS);
    }

    @Override

Review comment (suggestion):
Changing visibility from private to public exposes internal implementation details. Consider using a protected modifier instead if the method only needs to be accessible to subclasses.
```suggestion
    protected void start() {
```

Code after:
    AbstractTimerTask(ChannelProvider channelProvider, HashedWheelTimer hashedWheelTimer, Long tick) {
        if (channelProvider == null || hashedWheelTimer == null || tick == null) {
            throw new IllegalArgumentException();
        }
        this.channelProvider = channelProvider;
        this.hashedWheelTimer = hashedWheelTimer;
        this.tick = tick;
        // do not start here because inheritor should set additional timeout parameters before doing task.
    }

    static Long lastRead(Channel channel) {
        return (Long) channel.getAttribute(HeartbeatHandler.KEY_READ_TIMESTAMP);
    }

    static Long lastWrite(Channel channel) {
        return (Long) channel.getAttribute(HeartbeatHandler.KEY_WRITE_TIMESTAMP);
    }

    static Long now() {
        return System.currentTimeMillis();
    }

    protected void start() {
        this.timeout = hashedWheelTimer.newTimeout(this, tick, TimeUnit.MILLISECONDS);
    }

    public synchronized void cancel() {
        this.cancel = true;
        this.timeout.cancel();
    }

    private synchronized void reput(Timeout timeout) {
        if (timeout == null) {
            throw new IllegalArgumentException();
        }

        if (cancel) {
            return;
        }

        if (hashedWheelTimer.isStop() || timeout.isCancelled()) {
            return;
        }

        this.timeout = hashedWheelTimer.newTimeout(timeout.task(), tick, TimeUnit.MILLISECONDS);
    }

    @Override
    public synchronized void run(Timeout timeout) throws Exception {
        Collection<Channel> channels = channelProvider.getChannels();
        for (Channel channel : channels) {