Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

自动监控应用代码中【 线程池循环引用】现象的可行性讨论 #366

Open
ruoan777 opened this issue Nov 28, 2023 · 3 comments
Labels
question Further information is requested

Comments

@ruoan777
Copy link
Contributor

ruoan777 commented Nov 28, 2023

首先感谢您使用 DynamicTp,如果对项目有任何疑问需要解答,请按照下述模板提问,建议使用 Markdown 语法

使用方面

问题背景

问题来源参见 4.2.2节

public Object doGet() {
  ExecutorService threadPool1 = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(100));
  CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
  //do sth
    return CompletableFuture.supplyAsync(() -> {
        System.out.println("child");
        return "child";
      }, threadPool1).join();//子任务
    }, threadPool1);
  return cf1.join();
}

如上代码块所示,doGet方法第三行通过supplyAsync向threadPool1请求线程,并且内部子任务又向threadPool1请求线程。threadPool1大小为10,当同一时刻有10个请求到达,则threadPool1被打满,子任务请求线程时进入阻塞队列排队,但是父任务的完成又依赖于子任务,这时由于子任务得不到线程,父任务无法完成。主线程执行cf1.join()进入阻塞状态,并且永远无法恢复。

文章中也提到了解决方案:为了修复该问题,需要将父任务与子任务做线程池隔离,两个任务请求不同的线程池,避免循环依赖导致的阻塞。

具体问题:除了线程池隔离这样的人为约定,有没有办法通过代码实现【线程池循环引用】的自动监控?

尝试扩展了下 ExecutorAware,在execute方法里面,将提交任务的线程所对应的线程池名称记录下来并绑定到任务上,然后在beforeExecute中,获取当前实际执行的线程池的名称,和任务中绑定的名称做对比,如果相等,则认为发生了【线程池循环引用】。

这样的方式,解决父子任务【AA】场景是没有问题的,但是如果是【ABA】这样的方式就无能为力了(如下),想知道这个问题有办法解决吗?

    private void test() {
        DtpRegistry.getDtpExecutor("dtp1").submit(() -> {
            System.out.println("--------------------");
            System.out.println("in dtp1");
            System.out.println("--------------------");
            DtpRegistry.getDtpExecutor("dtp2").submit(() -> {
                System.out.println("--------------------");
                System.out.println("in dtp2");
                System.out.println("--------------------");
                DtpRegistry.getDtpExecutor("dtp1").submit(() -> {
                    System.out.println("--------------------");
                    System.out.println("in dtp1");
                    System.out.println("--------------------");
                });
            });
        });
    }
@ruoan777 ruoan777 added the question Further information is requested label Nov 28, 2023
@yanhom1314
Copy link
Collaborator

yanhom1314 commented Nov 29, 2023

挺好的想法,我觉得可以用ttl做线程池场景下的上下文传递,任务提交后将当前线程名称保存到ThreadLocal中,是个list,执行前可以从ThreadLocal获取值来判断当前线程池名称是否包含,这样就可以通过包含关系来判断是否有嵌套引用吧。

@wysnxzm
Copy link

wysnxzm commented Jan 22, 2024

forkjoinpool

@littlesky007
Copy link
Contributor

这种问题,不仅仅存在单个接口内部,接口之间也可能存在线程池的循环嵌套。这个估计需要维护一个线程池引用树来判断线程池之间的嵌套关系

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants