同时向一个URL发送多个POST请求

3

主要目标是通过REST服务将xml文件从一个文件夹发送到Cassandra数据库。我想做的就是读取特定文件夹中的所有文件,并创建一个Worker对象,其中设置了文件路径。

while (RUNS > 0) {
            ExecutorService executor = Executors.newFixedThreadPool(N_THREADS);

            File dir = new File(PATH_TO_SAMPLES);
            File[] listFiles = dir.listFiles();

            if (listFiles != null) {

                for (File file : listFiles) {

                    Worker worker = new Worker();
                    worker.setPath(file.toPath());

                    executor.submit(worker);
                }
            }

            executor.shutdown();

            // Wait until all threads are finish
            while (!executor.isTerminated()) {
            }

            Thread.sleep(1000);

            RUNS--;
        }

在此之后,执行器获取一个工作实例并转到目录中的下一个文件。 RUNS初始化为迭代的总数,默认值为100_000。 N_THREADS - 线程的总数,默认设置为100。

Worker类实现了Runnable接口。Run方法:

@Override
    public void run() {

        String url = getUrl();
        String payload = "xml_file_representation";

        MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();

        HttpClient client = new HttpClient();

        HttpConnectionManagerParams httpConnectionManagerParams = new HttpConnectionManagerParams();
        connectionManager.setParams(httpConnectionManagerParams);

        client.setHttpConnectionManager(connectionManager);

        PostMethod postMethod = new PostMethod(url);

        try {

            postMethod.setRequestHeader("User-Agent", USER_AGENT);
            postMethod.setRequestHeader("Content-Type", "application/xml");

            postMethod.setRequestEntity(new StringRequestEntity(payload, "application/xml", StandardCharsets.UTF_8.toString()));

            int statusCode = client.executeMethod(postMethod);

            InputStream body = postMethod.getResponseBodyAsStream();

            if (statusCode == HttpStatus.SC_OK) {

                //OK
            }

        } catch (Exception e) {
            LOG.error("POST: ERROR!");
        } finally {
            postMethod.releaseConnection();
            connectionManager.shutdown();
        }
    }

如果我删除等待,即在run结束时删除Thread.sleep(1000);,当发送了约16_000个请求时,我会收到一个异常:
java.net.BindException: Address already in use

这与客户端套接字上的BindException:地址已在使用中非常相似。

无论如何,被接受的答案对我没有帮助。我不知道该怎么做才能关闭那些“连接”,以防止出现该错误。

像Thread.sleep()这样的解决方法也不是一个好的解决方案。感谢任何帮助或建议。


好奇。只是猜测,但根据您的描述,创建线程可能正在超前关闭它们;而且您正在用尽可用端口。不过,看起来您在终止线程之前正确地关闭了HTTP客户端,这应该可以避免这种情况。可能您的finally块正在调用本机代码,但在线程返回之前无法执行。 - Elliotte Rusty Harold
1
@Berger 完美的建议,谢谢。使用 Method A(全局 HttpClient 在所有线程之间共享)解决了我的问题。 - dofamin
@ElliotteRustyHarold 不确定真正的原因是什么,但全局 HttpClient 和 MultiThreadConnManager 已经解决了我的问题。 - dofamin
1个回答

0

为每个工作线程创建一个连接管理器会破坏连接管理器的目的。根据Berger在其他帖子中的链接,它应该在线程之间共享。 这就像没有任何东西一样。

你的操作系统在关闭后保持套接字处于挂起状态。除了使用那个其他问题中提出的设计重新使用套接字(连接),你别无选择。

除非你想冒险尝试Socket.setSOLinger() TCP选项SO_LINGER(零)-当需要时

Thread.sleep(1000)显然不是可行的选择,因为另一天你可能需要超过1秒...或者在其他情况下操作系统可能会改变挂起套接字的数量。


选择了这个答案作为采纳,Berger的评论也是有用建议的一部分。谢谢。 - dofamin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接