heartbeat threads blocks process shutdown because its hashed-wheel-timer is non-daemon thread.
@Override
    @Deprecated
    public void reset(org.apache.dubbo.common.Parameters parameters) {
        reset(getUrl().addParameters(parameters.getParameters()));
    }
    @Override
    public void reconnect() throws RemotingException {
        client.reconnect();
    }
    @Override
    public Object getAttribute(String key) {
        return channel.getAttribute(key);
    }
    @Override
    public void setAttribute(String key, Object value) {
        channel.setAttribute(key, value);
    }
    @Override
    public void removeAttribute(String key) {
        channel.removeAttribute(key);
    }
    @Override
    public boolean hasAttribute(String key) {
        return channel.hasAttribute(key);
    }
    private void startHeartbeatTimer() {
        AbstractTimerTask.ChannelProvider cp = () -> Collections.singletonList(HeaderExchangeClient.this);
        long heartbeatTick = calculateLeastDuration(heartbeat);
        long heartbeatTimeoutTick = calculateLeastDuration(heartbeatTimeout);
        HeartbeatTimerTask heartBeatTimerTask = new HeartbeatTimerTask(cp, heartbeatTick, heartbeat);