我有一个包含数十亿条记录的ArrayList,我遍历每条记录并将其发布到服务器。在每次迭代中,调用的方法如下:

public void sendNotification(String url, String accountId, String accountPwd, String jsonPayLoad,
            int maxConnections) {
        notificationService = Executors.newFixedThreadPool(maxConnections);
        notificationService.submit(new SendPushNotification(url, accountId, accountPwd, jsonPayLoad));
        notificationService.shutdown();

    }

我的SendPushNotification类如下:
public class SendPushNotification implements Runnable {

    String url;
    String accountId;
    String accountPwd;
    String jsonPayLoad;

    public SendPushNotification(String url, String accountId, String accountPwd, String jsonPayLoad) {
        this.url = url;
        this.accountId = accountId;
        this.accountPwd = accountPwd;
        this.jsonPayLoad = jsonPayLoad;

    }
    public void run() {

        HttpsURLConnection conn = null;
        try {

            StringBuffer response;
            URL url1 = new URL(url);
            conn = (HttpsURLConnection) url1.openConnection();
            // conn.setReadTimeout(20000);
            // conn.setConnectTimeout(30000);
            conn.setRequestProperty("X-Account-Id", accountId);
            conn.setRequestProperty("X-Passcode", accountPwd);
            conn.setRequestProperty("Content-Type", "application/json");
            conn.setDoOutput(true);
            conn.setRequestMethod("POST");

            OutputStream out = new BufferedOutputStream(conn.getOutputStream());
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
            writer.write(jsonPayLoad);
            writer.close();
            out.close();
            int responseCode = conn.getResponseCode();

            System.out.println(String.valueOf(responseCode));
            switch (responseCode) {
            case 200:
                BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
                String inputLine;
                response = new StringBuffer();
                while ((inputLine = in.readLine()) != null) {
                    response.append(inputLine);
                }
                in.close();
                System.out.println(response.toString());
            }
        } catch (IOException ez) {
            ez.printStackTrace();

        } finally {
            if (conn != null) {
                try {
                    conn.disconnect();
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

    }

所以这里出了什么问题,我怀疑我必须在一个不错的系统配置上运行它。基本上我想了解我的代码是否有问题?

最佳答案

方法错误!循环播放:

notificationService = Executors.newFixedThreadPool(maxConnections);

糟糕的想法!您为什么打算创建ThreadPools的十亿个;提交一项任务然后将其关闭?这就像每次烟灰缸装满时都购买新的法拉利...

请理解:您的简单代码创建了很多对象;一次循环迭代后,它们全部消失了。含义:他们有资格进行垃圾收集。换句话说:您不断以极高的速率创建垃圾。您真的感到惊讶,这样做会使您陷入“内存不足”的境地?

相反,使用一个 ThreadPool并向其中提交数十亿个请求!

除此之外,即使那也不是一个好主意。为每个条目打开与服务器之间的一个网络连接只会而不是扩展到十亿个条目:真正的 解决方案要求您退后一步,想一想以“合理方式”工作的所有事物。例如,您应该考虑在服务器上创建某种“批量”或“流”接口(interface)。在客户端上迭代数十亿个条目的文件,并与服务器建立数十亿个连接,这真是太疯狂了!

因此,不要这样做:
loop:
  open connection / push ONE item / close connection

你最好去:
open connection / push all items / close connections

甚至除此之外,您甚至可以研究传输压缩的二进制数据。含义:在客户端压缩文件,以blob形式发送;并在服务器端提取/处理它。

这里有很多选择空间;但请放心:您当前的“内存不足”异常只是由“不合适的”设计引起的一种症状。

编辑:给出您的评论,我的(个人)建议:
  • 显然:使用一个线程池(可能基于3个线程构建),并将您的Runnables推送到该共享池中
  • 然后开始仔分割析。考虑到您打算处理数十亿个条目的事实,每毫秒可能会很重要。换句话说:进行合理的测试,找出解决方案的“好”程度。如果无法解决问题,做概要分析以找到需要改进的地方。
  • 要了解的关键点:您可能可以微调事物,在这里获得1%,在那获得5%。但是很可能所有这些都不够好。当您执行十亿次操作时,它们应该是真的很快;否则那个因素会杀死你...
  • 关于java - ExecutorService发出内存不足错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42108351/

    10-11 20:45