java 中的执行程序终止递归如何?

How is an executor termination recursion in java?

这是一个程序,它使用递归读取以前格式的信息站点,executor.It 工作正常,我的问题是测试程序是否完成和成功通知。

public class NewClass { 

    static String levels[] = { "div.col-md-9 li a", "div#sidebar ul li a" };    
    static String links = "";   

    private void getRecursive(String href, int level, final ExecutorService executor) { 

        if (level > levels.length - 1) {    
            return; 
        }   

        Document doc;   
        try {   
            doc = Jsoup.connect(href).get();    
            Elements elements = doc.select(levels[level]);  
            final int flevel = ++level; 
            for (final Element element : elements) {    
                executor.execute(new Runnable() {   
                    @Override   
                    public void run() { 
                        if (!element.attr("href").isEmpty()) {  
                            links += element.attr("abs:href") + "\n";   
                            System.out.println(links);  
                            getRecursive(element.attr("abs:href"), flevel, executor);   
                        }   
                    }   
                }); 
            }   
        } catch (IOException e1) {  
            e1.printStackTrace();   
        }   
    }   

如果levels.length = 1,规则执行器运行良好,但如果levels.length>1将出现错误:线程异常 "pool-1-thread-138" java.util.concurrent.RejectedExecutionException

    public static void main(String[] args) {    
    try {
        ExecutorService executor = Executors.newFixedThreadPool(5);
        new NewClass().getRecursive("http://www.java2s.com/", 0, executor);
        executor.shutdown();
        executor.awaitTermination(1, TimeUnit.HOURS);
        if (executor.isTerminated()) {
            JOptionPane.showMessageDialog(null, "Success");
        }
    } catch (Exception ex) {
        Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
    }
}   
}

问题是您在调用 executor.shutdown() 之后调用 executor.executeawaitTermination 方法仅等待调用 shutdown 之前提交的任务。

这就是发生这种情况的原因:

  • 假设程序在线程 main 上启动。
  • executor.execute 的第一个电话是在 main
  • 假设执行程序现在在 thread-pool-1 上运行,它还调用 executor.execute
  • 但在执行这些新任务之前,我们跳回到 main 并调用 executor.shutdown
  • 执行器可能会再次开始执行任务,这次可能是 thread-pool-2,它会尝试调用 executor.execute。但是,executor.shutdown() 已经被调用,因此抛出 java.util.concurrent.RejectedExecutionException

有几种方法可以解决这个问题:

  1. 在这种情况下使用执行器可能有点矫枉过正;只做单线程可能就足够了。
  2. 也许可以重构代码,以便最后的 executor.execute 可以调用 executor.shutdown。但是,如果没有明确的最后调用,这将是不可能的。
  3. 如果您绝对需要在主线程之外执行此操作,您可以在其自己的线程中执行整个递归调用:

    public static void main(String[] args) {
        try {
            ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    NewClass.getRecursive("http://www.java2s.com/", 0);
                }
            });
            executor.shutdown();
            executor.awaitTermination(1, TimeUnit.HOURS);
            if (executor.isTerminated()) {
                JOptionPane.showMessageDialog(null, "Success");
            }
        }
        catch (Exception ex)
        {
            Logger.getLogger(NewClass.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    

    private static class NewClass {
    
        static String levels[] = { "div.col-md-9 li a", "div#sidebar ul li a" };
        static String links = "";
    
        private static void getRecursive(String href, int level) {
    
            if (level > levels.length - 1) {
                return;
            }
    
            Document doc;
            try {
                doc = Jsoup.connect(href).get();
                Elements elements = doc.select(levels[level]);
                final int flevel = ++level;
                for (final Element element : elements) {
                    if (!element.attr("href").isEmpty()) {
                        links += element.attr("abs:href") + "\n";
                        System.out.println(links);
                        getRecursive(element.attr("abs:href"), flevel);
                    }
                }
            }
            catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }
    

您关闭ExecutorService后无法提交任何新任务,递归似乎在您处理完所有级别后停止(之后您不提交任何新任务),您可以这样做:

if (level > levels.length - 1) {    
    executor.shutdown();
    return; 
}