ExecutorService发出内存错误

Use*_*er3 1 java multithreading

我有一个有数十亿条记录的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();

    }
Run Code Online (Sandbox Code Playgroud)

我的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();
                }
            }
        }
    }

    }
Run Code Online (Sandbox Code Playgroud)

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

Gho*_*ica 7

错误的做法!循环:

notificationService = Executors.newFixedThreadPool(maxConnections);
Run Code Online (Sandbox Code Playgroud)

是个主意!为什么要打造数十亿个ThreadPools; 提交一个任务然后关闭它?!这就像每次灰盘都满了就买一辆法拉利......

请理解:您的简单代码会创建大量对象; 并且所有这些都在一次循环迭代后消失.含义:他们有资格进行垃圾收集.换句话说:你经常以非常高的速度创造垃圾.你真的很惊讶,这样做会让你陷入"记忆力不足"的境地吗?

相反,使用一个 ThreadPool并将您的数十亿请求提交给它!

除此之外,即使这不是一个好主意.每个条目打开一个到您服务器的网络连接,根本不会扩展到数十亿条目:一个真正的解决方案要求您退后一步,思考一些以"合理的方式"端到端工作的东西.例如,您应该考虑在服务器上创建某种"批量"或"流式"接口.迭代客户端上的数十亿条目文件,并与服务器建立数十亿的连接很遗憾,疯了!

所以不要这样做:

loop:
  open connection / push ONE item / close connection
Run Code Online (Sandbox Code Playgroud)

你最好去:

open connection / push all items / close connections
Run Code Online (Sandbox Code Playgroud)

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

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

编辑:鉴于您的意见,我的(个人)建议:

  • 显然:使用一个线程池(可能构建在3个线程上)并将Runnables推送到该共享池中
  • 然后开始仔细分析.鉴于您打算处理这些数十亿条目,每毫秒可能会计算.换句话说:进行合理的测试,找出解决方案的"好"程度.如果它没有成功; 进行分析以找到需要改进的地方.
  • 要理解的关键是:你可以微调一下,在这里获得1%,在那里获得5%; 但很可能会发生所有这些都不够好.当你做十亿次事情时,它们应该非常快; 否则那个因素会杀了你......

  • 别客气.我提出了一些更新.我想你应该先做测量,以评估这种架构*是否可以在理论上解决.如果您发现"这将永远不会扩展",那么除了**改变**整个架构之外别无选择.当服务器不能支持要求时(使用数十亿条目),使用"此服务器"有什么意义.换句话说:你想解决你的问题.如果"那个服务器"阻止解决方案,那么它必须去! (2认同)