【问题标题】:Java Thread in Multi Threading Hang for ever, without throwing any exception多线程中的 Java 线程永远挂起,不会抛出任何异常
【发布时间】:2016-12-11 23:22:59
【问题描述】:

我有一个 java 代码来废弃页面的内容。一次我执行 2500 个线程,每个线程有 100 个要废弃的 url。所有线程都成功执行,但很少有线程永远挂起而不抛出任何异常。使用 ubuntu 作为生产服务器。 代码卡在下面一行:

InputStream in = urlConnection.getInputStream();

我在做连接和读取超时,这是有效的。即使线程很少,读取超时也不起作用,它会永远挂起。 我已经尝试过很多工作,但都失败了。

我什至使用 thread.stop()杀死了挂起的线程(不推荐的方法)但是挂起的线程 tcp 连接在 linux 服务器上仍然存在

java    7325 root 2675u  IPv4          284078467        0t0       TCP scrapper-new-instance-2.c.quantum-tracker-93805.internal:37068->104.131.210.5:22225 (ESTABLISHED)
java    7325 root 2688u  IPv4          284077787        0t0       TCP scrapper-new-instance-2.c.quantum-tracker-93805.internal:38132->104.131.210.5:22225 (ESTABLISHED)
java    7325 root 2723u  IPv4          284057771        0t0       TCP scrapper-new-instance-2.c.quantum-tracker-93805.internal:43661->104.131.210.5:22225 (ESTABLISHED)

任何人有想法,我可以如何调试和修复这个问题?

下面是代码片段:

    int counter = 0;
    int maxAttempts = (config.getProperty("maxAttempts") != null ? Integer.parseInt(config
                .getProperty("maxAttempts")) : 100);
    Proxy proxy = null;
    while (counter < maxAttempts) {
        try {
            Type proxyType = Proxy.Type.HTTP;
            String proxyIP = "";
            int proxyPort;

            int proxyIndex = getRandomNumber(1, httpProxies.size());

            if(httpProxies.get(proxyIndex).split(":").length == 4){
                proxyIP = httpProxies.get(proxyIndex).split(":")[0];
                proxyPort = Integer.parseInt(httpProxies.get(proxyIndex).split(":")[1]);

                if (httpProxies.get(proxyIndex).split(":").length == 3) {
                    if (httpProxies.get(proxyIndex).split(":")[2].toLowerCase().contains("socks"))
                        proxyType = Proxy.Type.SOCKS;
                }
            }else{
                counter = counter - 1;
                throw new Exception("Escapeing for IP --- "+httpProxies.get(proxyIndex));

            }

            URL url = new URL(urlSring);
            InetSocketAddress inetSocketAddress = new InetSocketAddress(proxyIP, proxyPort);
            proxy = new Proxy(proxyType,inetSocketAddress);

            int userAgentIndex = getRandomNumber(1, userAgents.size());

            logger.info("Attempt = " + counter + " using proxy " + httpProxies.get(proxyIndex) + " (" + proxyType.name()
                        + ") for url " + urlSring);

            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(proxy);

            if (config.getProperty("connectionTimeoutInMilliSecs") != null)
                urlConnection
                            .setConnectTimeout(Integer.parseInt(config.getProperty("connectionTimeoutInMilliSecs")));
            else
                urlConnection.setConnectTimeout(CONNECTION_TIMEOUT_VALUE);

            if (config.getProperty("readTimeoutInMilliSecs") != null)
                urlConnection.setReadTimeout(Integer.parseInt(config.getProperty("readTimeoutInMilliSecs")));
            else
                urlConnection.setReadTimeout(READ_TIMEOUT_VALUE);


            System.setProperty("http.agent", "");

            urlConnection.setRequestProperty("User-Agent", "");
            urlConnection.setRequestProperty("User-Agent", userAgents.get(userAgentIndex));
            urlConnection.addRequestProperty("Accept-Encoding", "gzip, deflate, br"); // to avoid server returned http response code 403
            urlConnection.setInstanceFollowRedirects(true);

            //Few  Thread hang here for ever
            InputStream in = urlConnection.getInputStream();

            if(null !=  urlConnection.getContentEncoding() && urlConnection.getContentEncoding().equals("gzip")){
                in = new GZIPInputStream(in);
            }

            String output = IOUtils.toString(in, Charset.forName("UTF-8").name());

            logger.info("Proxy Address:-"+proxy.address()+ " HTTP Response Code : " + urlConnection.getResponseCode() + " HTTP Response Message : "
                        + urlConnection.getResponseMessage() + " for url ---" + urlSring);



            logger.info("Success scraping for url --- "+urlSring+ " --- using proxy --- "+httpProxies.get(proxyIndex));
            // Close Input Stream
            if(in != null){
                in.close();
            }

            // Close url connection and release underlying socket if exists.
            if(urlConnection != null){
                urlConnection.disconnect();
            }

            url = null;
            urlConnection = null;
            return output;

        } catch (Exception e) {
            logger.info(e);
            counter++;
            /*
             * logger.info("Exception : " + e.getMessage() + " while using proxy " + proxy.address() +
             * ".Trying next proxy.");
             */

            if (config.getProperty("shouldSleepBetweenRequests") != null
                        && config.getProperty("shouldSleepBetweenRequests").equalsIgnoreCase("true")) {
                Random r = new Random();
                int low = config.getProperty("minSleepTime") != null ? Integer.parseInt(config
                            .getProperty("minSleepTime")) : 0;
                int high = config.getProperty("maxSleepTime") != null ? Integer.parseInt(config
                            .getProperty("maxSleepTime")) : 5;
                int timeToSleep = r.nextInt(high - low) + low;
                logger.info("Sleeping for " + timeToSleep + " seconds ... ");
                try {
                    Thread.sleep(timeToSleep * 1000);
                } catch (InterruptedException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    if (counter >= maxAttempts)
        logger.info("Stoping after " + maxAttempts + " attempts ...for url "+ urlSring);

    return "";

请分享您的想法,并告诉我如何解决此问题。 我不想杀死挂起的线程,而是如果可能的话,我想为这种情况实现一些超时。

【问题讨论】:

    标签: java linux multithreading http tcp


    【解决方案1】:

    尝试使用更复杂的 HTTP 客户端,即使用Jetty,您可以为套接字连接设置超时:

    HttpClient httpClient = new HttpClient();
     httpClient.start();
    
     //socket connection timeout in ms
     httpClient.setConnectTimeout(500)
    
     // One liner:
     httpClient.GET("http://localhost:8080/").getStatus();
    
     // Building a request with a timeout for request/response conversation
     ContentResponse response = httpClient.newRequest("http://localhost:8080")
             .timeout(5, TimeUnit.SECONDS)
             .send();
    

    【讨论】:

    • 我会尝试使用 jetty,我已经尝试使用 Apache Http Client 并遇到了类似的问题。
    猜你喜欢
    • 2018-09-18
    • 1970-01-01
    • 2020-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多