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

时间:2015-11-04 02:34:24

标签: java recursion executorservice executor termination

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

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 将出现错误:线程中的异常"池 - 1线程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);
    }
}   
}

2 个答案:

答案 0 :(得分:3)

问题是您在致电executor.execute后正在致电executor.shutdown()awaitTermination方法仅等待在调用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();
            }
        }
    }
    

答案 1 :(得分:3)

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

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