如何将递归解决方案转换为非递归

传统的解决方案,这里不再赘述。但是传统课堂上的解决方案,可能并不能满足要求。因为,可能我们在使用的是第三方框架,

我们的业务逻辑是写在三方框架的回调函数中的,代码由三方库调用。顺带一提,这也是spring框架开创的模式,不是由用户调用第三方框架,而是由第三方框架来调用用户代码。

例如如下代码片段:

    void onIOEvent(final int readyOps) throws IOException {
        if ((readyOps & SelectionKey.OP_CONNECT) != 0) {
            if (socketChannel.isConnectionPending()) {
                socketChannel.finishConnect();
            }
            //if cas return true,that means connect timeout task has not been triggered,timeoutTask can be cancled.
            if (timeOutState.compareAndSet(TimeOutState.NOTSET, TimeOutState.CANCLE)) {
            	getWheelTimeOut().cancel();//cancle connect timeout task
            	setWheelTimeOut(null);
                final InternalDataChannel dataChannel = dataChannelFactory.create(
                        key,
                        socketChannel,
                        sessionRequest.remoteEndpoint,
                        sessionRequest.attachment);
                //use HashedWheelTimer to trigger read timeout task
                SingleCoreIOReactor.timeWheel.newTimeout(getSocketTimeoutTask(dataChannel), dataChannel.getSocketTimeout(), TimeUnit.MILLISECONDS);
                key.attach(dataChannel);
                sessionRequest.completed(dataChannel);
                dataChannel.handleIOEvent(SelectionKey.OP_CONNECT);
            }
        }
    }
    
    private TimerTask getSocketTimeoutTask(InternalDataChannel dataChannel){
    	return new TimerTask() {

			@Override
			public void run(WheelTimeout timeout) throws Exception {
				final long currentTime = System.currentTimeMillis();
				if(dataChannel != null && !dataChannel.isClosed() && dataChannel.checkTimeout(currentTime)){
					final long delayTime = getLastReadTime() + dataChannel.getTimeout() - currentTime;
					SingleCoreIOReactor.timeWheel.newTimeout(getSocketTimeoutTask(dataChannel),delayTime,TimeUnit.MILLISECONDS);
				}
			}
		};
    }

第一个语句中,使用时间轮算法启动一个定时任务。该定时任务被第三方框架调用,回调函数需要写在TimerTask子类的run方法

中。

我们的业务逻辑是,在run方法中,还需要进行业务逻辑的判断,如果发现满足条件,需要在回调函数中继续调用时间轮框架,传入TimerTask子类,进行延时逻辑处理。此处则必须使用递归处理了。

为了满足以上条件,我们写了一个getSocketTimeouTask方法,该方法返回一个TimerTask类。在run方法中,我们递归调用自身,达到run方法中继续调用延时框架进行延时处理的目的。

但是使用递归方式有一个严重的问题,栈溢出问题。该代码是进行socket读取超时判定,run方法中判定socket是否读超时(readtimeout),如果没有,则将下次的延时任务放入第三方框架,等待下次延时进行判断。如果socket一直未超时,将导致该递归方法不断递归下去,触发栈溢出。

netty3 增加了一个类,使用增加类的方式,可以将这个方法的递归问题回避掉。

思路如下:

public class ReadTimeoutTask implements TimerTask {
	
	private InternalDataChannel dataChannel;
	
	@Override
	public void run(WheelTimeout timeout) throws Exception {
		// TODO Auto-generated method stub
		final long currentTime = System.currentTimeMillis();
		if(dataChannel != null && !dataChannel.isClosed() && dataChannel.checkTimeout(currentTime)){
			final long delayTime = dataChannel.getLastReadTime() + dataChannel.getTimeout() - currentTime;
			SingleCoreIOReactor.timeWheel.newTimeout(this,delayTime,TimeUnit.MILLISECONDS);
		}
	}

	public ReadTimeoutTask(InternalDataChannel dataChannel) {
		this.dataChannel = dataChannel;
	}
	
	

}

在该类的run方法回调时将自身传入第三方框架中。每次可以正常调用完毕run方法。新的延时任务是另外启动的,将this

传入,而不是像前一个方法,将自身方法递归传入。规避了递归问题,是一个非常牛逼的思路。

此时只需要将

SingleCoreIOReactor.timeWheel.newTimeout(getSocketTimeoutTask(dataChannel), dataChannel.getSocketTimeout(), TimeUnit.MILLISECONDS);

修改为:

SingleCoreIOReactor.timeWheel.newTimeout(new ReadTimeoutTask(dataChannel), dataChannel.getSocketTimeout(), TimeUnit.MILLISECONDS);

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值