Java StringBuilder大量数据块线程

时间:2015-03-27 10:24:51

标签: java stringbuilder

我正在运行一个小程序,处理数据库中大约215K的记录。这些记录包含JmlB用于编组和解组对象的xml。

我正在运行的程序试图找到由于遗留而无法解组的xml。每次我有unmarshal异常时,我都会在arraylist中保存包含xml的异常消息。最后,我想发送一封包含所有失败记录的邮件,并附带原因异常消息。所以我使用arraylist中的消息和StringBuilder来组成电子邮件正文。

然而,在大约75K失败的情况下,当我构建主体时,StringBuilder刚刚停止追加到for循环中的某个点并且线程被阻塞。我后来改变了我的方法,不再从异常消息中附加xml,但我仍然不清楚为什么它不起作用。

可能是VM内存不足,或者字符串只能达到一定的大小(我怀疑在64位时代肯定是这样)。有没有更好的方法可以解决这个问题?我打算将StringBuilder发送到我的服务而不是先将字符串保存在arraylist中,但那将是一个如此脏的界面:(

任何建筑见解都将受到赞赏。

EDIT 按照这里的要求,这不是火箭科学。假设失败列表包含大约75K个条目,每个条目包含一个xml的avg 500到1000行

  private String createBodyMessage(List<String> failures) {
    StringBuilder builder = new StringBuilder();
    builder.append("Failed operations\n");
    builder.append("=================\n\n");
    for (String failure : failures) {
      builder.append(failure);      
      builder.append("\n");      
    }
    return builder.toString();
  }

3 个答案:

答案 0 :(得分:2)

您可能只是成功

int sizeEstimate = failures.size() * 20;
StringBuilder builder = new StringBuilder(sizeEstimate);
builder.append("Failed operations\n");
builder.append("=================\n\n");
while (!failures.isEmpty()) {
    builder.append(failures.remove(0));      
    builder.append('\n');      
}

这样做不会调整StringBuilder的内部缓冲区的大小,并且会消耗失败以减少内存。

如果文字太大,可能无法解决问题。

压缩附件是标准程序。

答案 1 :(得分:1)

StringBuffer 基于数组结构,数组中的最大单元格数为 2 ^ 31-1
达到这个大小通常会在Java 7上引发错误,但我不太确定

解决方法是在达到StringBuffer的固定大小之前数据交换到文件

答案 2 :(得分:1)

  

可能是VM内存不足,

如果你填满了堆,你会得到OutOfMemoryError例外。

  

或者字符串只能是一定的大小(我怀疑在64位时代肯定)。

实际上,是的。 Java StringStringBuilder最多可包含2 ^ 32-1个字符 1

  

有没有更好的方法可以解决这个问题?我打算将StringBuilder发送到我的服务,而不是先将字符串保存在arraylist中......

如果真正的问题是字符串的串联太大而无法保存在StringBuilder中,那将无济于事。

实际上,更好的方法是将字符串流式传输到PipedOutputStream,然后使用相应的PipedInputStream构建一个MimeBodyPart,然后将其附加到电子邮件中。您也可以在流堆栈中包含压缩器。

更好的方法不会尝试发送数十亿字节的错误数据作为电子邮件附件。将它们保存为可以提取(或其他)的文件如果电子邮件收件人想要它们。


1 - 令人惊讶的是,javadoc似乎没有明确说明这一点。但是,String.length()返回int,各种字符串操作方法使用int参数来指定偏移量和长度。当然,StringStringBuilder的标准实现使用单个char[]作为后备存储,并且JLS JVM规范。