递归算法_使用Java ThreadLocals的意外递归保护

递归算法

递归算法

对于那些使用第三方工具来尝试扩展它们而又不完全了解它们的人来说,这是一个小技巧。 假定以下情况:

  • 您想扩展一个公开分层数据模型的库(假设您要扩展Apache Jackrabbit )
  • 该库在访问内容存储库的任何节点之前会内部检查访问权限
  • 您想实现自己的访问控制算法
  • 您的访问控制算法将访问内容存储库的其他节点
  • …进而会再次触发访问控制
  • …进而将再次访问内容存储库的其他节点

…无限递归,如果不递归广度优先,则可能会导致StackOverflowError

现在,您有两个选择:

  1. 花时间,坐下来,了解内部原理,并正确地做。 到达自己的扩展名后,您可能不应该递归到访问控制中。 在扩展Jackrabbit的情况下,这可以通过使用系统会话在访问控制算法中进一步访问节点来完成。 系统会话通常绕过访问控制。
  2. 急躁,想快速获得结果,并通过技巧来防止递归

当然,您确实应该选择选项1。但是,谁有时间了解所有内容?

这是实现该技巧的方法。

/**
 * This thread local indicates whether you've
 * already started recursing with level 1
 */
static final ThreadLocal<Boolean> RECURSION_CONTROL
    = new ThreadLocal<Boolean>();
 
/**
 * This method executes a delegate in a "protected"
 * mode, preventing recursion. If a inadvertent
 * recursion occurred, return a default instead
 */
public static <T> T protect(
        T resultOnRecursion,
        Protectable<T> delegate)
throws Exception {
 
    // Not recursing yet, allow a single level of
    // recursion and execute the delegate once
    if (RECURSION_CONTROL.get() == null) {
        try {
            RECURSION_CONTROL.set(true);
            return delegate.call();
        }
        finally {
            RECURSION_CONTROL.remove();
        }
    }
 
    // Abort recursion and return early
    else {
        return resultOnRecursion;
    }
}
 
/**
 * An API to wrap your code with
 */
public interface Protectable<T> {
    T call() throws Exception;
}

在此用法示例中可以很容易地看出这一点:

public static void main(String[] args)
throws Exception {
    protect(null, new Protectable<Void>() {
        @Override
        public Void call() throws Exception {
 
            // Recurse infinitely
            System.out.println("Recursing?");
            main(null);
 
            System.out.println("No!");
            return null;
        }
    });
}

main()方法的递归调用将被保护方法终止,并提早返回,而不是执行call() 。 还可以通过使用ThreadLocals Map进一步详细说明此思想,允许指定各种键或上下文以防止递归。 然后,您还可以将Integer放入ThreadLocal ,在递归时将其递增,最多允许N个递归级别。

static final ThreadLocal<Integer> RECURSION_CONTROL
    = new ThreadLocal<Integer>();
 
public static <T> T protect(
        T resultOnRecursion,
        Protectable<T> delegate)
throws Exception {
    Integer level = RECURSION_CONTROL.get();
    level = (level == null) ? 0 : level;
 
    if (level < 5) {
        try {
            RECURSION_CONTROL.set(level + 1);
            return delegate.call();
        }
        finally {
            if (level > 0)
                RECURSION_CONTROL.set(level - 1);
            else
                RECURSION_CONTROL.remove();
        }
    }
    else {
        return resultOnRecursion;
    }
}

但是再说一次。 也许您只需要花几分钟时间,并了解主机库的内部机制是如何工作的,并从一开始就将事情做好……一如既往,在使用技巧和黑客手段时!

翻译自: https://www.javacodegeeks.com/2013/04/inadvertent-recursion-protection-with-java-threadlocals.html

递归算法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值