递归调用 之 无限死锁

直接干货吧。

什么是 “ 无限死锁”?

这个词是我的叫法,具体应该怎么称呼,知道的童鞋望告知我。我只来说它的现象:进入递归调用后,因为某种超出预期的原因,而使得程序段无法退出,在递归中无限循环执行的这样一种状态,我称之为“无限死锁”。

明明我写的代码没问题啊,为什么会有这种情况存在呢?

所有代码,从出发点上来说,均是基于某种假设,基于某种具体业务逻辑的实现。那么,如果代码本身所基于的环境(数据环境)超出了预期,那么就有可能出现这种情况。

 

来点代码干货说明下:

	protected void siphonAllChildSort(List<Map> sourceList, List<Map> destList, String rootId) {
		siphonAllChild(sourceList, destList, rootId);
		Collections.sort(destList, new Comparator<Map>() {
			@Override
			public int compare(Map o1, Map o2) {
				return (Integer) o1.get("GROUPLEVEL") - (Integer) o2.get("GROUPLEVEL");
			}
		});
	}

	private void siphonAllChild(List<Map> sourceList, List<Map> destList, String rootId) {

		if (sourceList == null || sourceList.size() == 0) {
			return;
		}

		for (Map<String, Object> src : sourceList) {
			if (rootId.equals(ObjectUtils.toString(src.get("PID")))) {
				destList.add(src);
				siphonAllChild(sourceList, destList, src.get("ID").toString());
			}
		}
	}

如上的代码,是我在项目中截取到的真实代码段。它的作用,如下:

1,根据根节点 rootId,去 sourceList 中抽取这个根下所有数据,并将其放入 destList 中,每个对象通过  子.PID=父.ID  关系关联。

2,对取得的数据根据 GROUPLEVEL 排序。

 

对头,看懂代码了,感觉没毛病。然而呢?

其实是理想状态下没毛病,如果 PID  和 ID  通过一系列相互指向,形成循环了呢?是的“递归调用之无限死锁“!甚至,有些情况下,内存被耗尽,系统全面停摆。

那是数据的问题,我的程序没bug!别狡辩了,无论数据如何,你的代码让整个系统死掉了。。。

 

这种数据怎么来的?

也许开发前台操作这个数据的界面的童鞋没多想,开发出的功能,操作上允许循环指向。

也许客户觉得前台操作麻烦,直接去库里根据自己的理解改了数据,然而手误,输入错了。

很多也许。。。

 

怎样避免?看代码:

	protected void siphonAllChildSort(List<Map> sourceList, List<Map> destList, String rootId) {
		siphonAllChild(500, sourceList, destList, rootId);
		Collections.sort(destList, new Comparator<Map>() {
			@Override
			public int compare(Map o1, Map o2) {
				return (Integer) o1.get("GROUPLEVEL") - (Integer) o2.get("GROUPLEVEL");
			}
		});
	}

	private void siphonAllChild(int loop, List<Map> sourceList, List<Map> destList, String rootId) {

		if (sourceList == null || sourceList.size() == 0 || loop == 0) {
			return;
		}

		for (Map<String, Object> src : sourceList) {
			if (rootId.equals(ObjectUtils.toString(src.get("PID")))) {
				destList.add(src);
				siphonAllChild(loop--, sourceList, destList, src.get("ID").toString());
			}
		}
	}

是的,核心就是,传入 loop 参数,并每次对其减一,当 loop == 0 时直接跳出。这样做,loop 的初始值设置就很有技巧了:你得设置一个你觉得能处理完正常数据的值。

这损失了递归调用的无限性!是的,但实际够用即可。虽然很多事情理论上有无限,但实际中,我们并不会用到无限。使用递归,只是为了不丑陋的把同样的代码copy 3次或者4次,仅此而已。

 

loop值的设置,又始问题回到了原点。还是我开头说过的话,所有的代码,出发点总是基于某种假设。

转载于:https://my.oschina.net/sxgkwei/blog/865734

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值