为什么 SocketTimeoutException 使我的程序冻结?

Why SocketTimeoutException makes my program freeze?

我给了我的程序超过 600 links,存储在一个 ArrayList 中以获得网页的标题,使用 JSoup(以及其他)。对于每个 link(使用 for 循环),我创建一个新线程(使用 thread.start())并通过我的程序传递 link,我在启动新线程之前等待我的线程完成(thread.join)(同时执行会导致一些问题,我这样做是为了防止意外的线程结束以停止其他 links 的执行) .

问题是有时,JSoup 抛出 SocketTimeoutException(我应该捕获),这使我的程序冻结。我不知道为什么执行停止甚至被 try/catch.

包围

这是我的一段代码,也许可以帮助您理解:

// In the method actionPerformed() of my JPanel

for(final String link : links)
{
    Thread t = new Thread()
    {
        public void run()
        {
            Analyzer.process(link);
        }
    };
    t.start();
    try 
    {
        t.join();
    } 
    catch (InterruptedException e) 
    {
        e.printStackTrace();
    }
}

在我的过程中:

// method process() of my Analyzer class
try 
{
    Document doc = Jsoup.connect(lien).userAgent("Mozilla").timeout(5*10000).get(); 
    //                    ^ EXCEPTION THROWN HERE ! ^

    title = doc.title();
}
catch (Exception e) 
{
    e.printStackTrace();
    erreurs+="Erreur lors de la lecture du titre\n";
}

很烦人,因为过程很长,我让它运行过夜,今天发现我的程序卡在第54link。 ^^' 提前谢谢你!

编辑 - 更新

SercanOzdemir 建议我使用 ExecutorService,而不是创建线程和创建 start()-join(),所以我尝试了 :

ExecutorService ex = Executors.newSingleThreadExecutor();
for(final String link : links)
{
    System.err.println("-- "+i+" --");              //DEBUG
    ex.execute(new Runnable(){
            @Override
            public void run(){
                try
                {
                    Analyzer.process(link);
                }
                catch( Exception e )
                {
                    e.printStackTrace();
                }

            }
    });
    i++;                                            //DEBUG
    }
ex.shutdown();

但它只打印我的调试 links。知道为什么它不 运行 我的流程吗?

为每个 link 打开一个新线程是一个非常糟糕的选择。

如果您想要多线程程序,请考虑使用ExecutionService

如果我们遇到您的问题,我宁愿完全按照下面的方式更改此程序,因为您在连接部分捕获异常并且不能保证您的异常已在此部分抛出..

new Runnable(){

            @Override
            public void run(){
                try{
                    // your codes
                }
                catch( Exception e ){
                    e.printStackTrace();
                }

            }
        }.run();

我没有用 jsoup 尝试过,但这是创建线程来执行任务并监视其状态的简单方法。

    ExecutorService executorService = Executors.newCachedThreadPool();
    Future future = null;
    for(final String link : links)
    {
        future = executorService.submit(new Runnable(){

        @Override
        public void run(){
            try{
               Analyzer.process(link);
            }
            catch( Exception e ){
                e.printStackTrace();
            }

        }
    });

        while(future != null
                && !future.isDone()
                && !future.isCancelled())
        {
            try {
                Thread.sleep(2000); // Or do something else
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    executorService.shutdown();

您更新后的问题中的代码将不起作用,因为您正在创建服务并立即覆盖它而不等待它完成。

ExecutorService ex = Executors.newSingleThreadExecutor();
for(final String link : links)
{
  System.err.println("-- "+i+" --");              //DEBUG
  ex.execute(new Runnable(){ //Here it is created
        @Override
        public void run(){
            try
            {
                Analyzer.process(link);
            }
            catch( Exception e )
            {
                e.printStackTrace();
            }

        }
});
i++;                                            //DEBUG
//a split second later this loop finishes and overwrites the service again
}
ex.shutdown();