Java 多线程应用程序中的新字符串(字节[])太慢

Java 多线程应用程序中的新字符串(字节[])太慢,java,string,multithreading,Java,String,Multithreading,我注意到当我从一个线程调用新字符串(byte[])时,速度非常快。但是当我从几个不同的线程调用它时,它会变得非常缓慢 例如,我有一个解析器,它调用新字符串(字节)。如果我按顺序调用解析器50次,每次解析大约需要100ms,但是如果我创建50个线程并调用解析,每次解析需要12000ms到21000ms!(在后面的线程中速度会变慢)。似乎字符串(字节)构造被定义为同步的 分析器跟踪瓶颈到新字符串(字节),事实上,当我将其更改为新字符串(“Hello”)时,解析器在多线程中的速度与在单线程中的速度一样

我注意到当我从一个线程调用
新字符串(byte[])
时,速度非常快。但是当我从几个不同的线程调用它时,它会变得非常缓慢

例如,我有一个解析器,它调用
新字符串(字节)
。如果我按顺序调用解析器50次,每次解析大约需要100ms,但是如果我创建50个线程并调用解析,每次解析需要12000ms到21000ms!(在后面的线程中速度会变慢)。似乎字符串(字节)构造被定义为同步的

分析器跟踪瓶颈到
新字符串(字节)
,事实上,当我将其更改为
新字符串(“Hello”)
时,解析器在多线程中的速度与在单线程中的速度一样快

有人知道为什么会这样吗?解决办法是什么

更新: 我的验证测试是错误的,因为Java编译器显然有一些内部优化,当我调用new
String(“Hello”)
时,它们共享字符串对象,而不是创建新的字符串对象。这就是为什么我做出改变时速度更快的原因。我将重写我的测试代码并更新这个问题

回答: 下面的@nafas和@peter答案都是正确的。字符串本身并不慢,但探查器错误地将其识别为瓶颈。真正的罪魁祸首是:

  • 具有比可用内核更多的线程
  • 垃圾收集器在操作过程中暂停执行,因为创建和销毁的临时对象太多。 交换
    如果RAM较低,JVM将与操作系统一起交换到HDD。增加可用性Xmx和Xms以获得更好的性能。

    我很确定,它不是
    字符串类
    ,因为它们是
    不可变的
    ,它们与同步或线程无关

    如果内核的数量相对较低(比如说2个),并且你有50个线程,那么速度就会降低相当大的一个因素。这是因为您在程序中创建了额外的复杂性

    每次CPU在线程中循环都会花费一些时间

    对于我通常使用的线程数的选择,没有经验法则:

    number of Cores + 1
    
    注意:


    如果你说有很多API调用,我会选择更多的线程,而如果线程纯粹使用CPU(正如你正在使用它们),那么我会选择更少的线程(
    threads=#cores+1

    这不是
    newstring()
    这会减慢您的进程,使其产生50个线程:D.线程数的约定通常是
    #CORE+1
    您是否尝试过使用较少的线程数?很确定你不会有50个coreshow你测量过这个数字吗?你能提供你的代码吗?cas测量中也可能存在问题。我认为这可能是因为您传递的是一个字节数组,必须使用正确的编码转换字节。使用字符串方法时,此编码任务相当长~4年前,我发现定制MongoDB驱动程序中存在性能瓶颈,事实上,MongoDB通过实现从字符串到UTF8的转换以及从字符串到UTF8的转换解决了这个问题。这可能与您的问题有关吗?@M.leRutte最近更改了子字符串,因此它实际上使用了一个新的字符数组。出于某些原因,请小心使用grepcode搜索结果可能会引用java 6。@我同意peter的观点,这可能是速度降低的另一个原因。字节[]必须非常大才能生效。如果它的顺序是“Hello”,那么这是一个非因素。由于算法创建和销毁了许多临时对象,内存确实是问题的一部分。我有足够多的内存,但垃圾收集器在操作中间会暂停以清除内存。使用Xmx是解决方案的一部分。我更新了问题以反映你的答案。我的电脑有8个内核。如果运行8线程,问题仍然存在。当我从8个线程调用新字符串(字节[])时,速度会比从单个线程调用慢20倍。您有/使用了多少内存?正如@peter提到的,可能是操作系统交换。还可以尝试使用较低的线程,看看效果如何!原来我只有4个物理核心。我的电脑列出了8个内核,但其中4个是虚拟内核,所以不要计算。你的回答是我问题的部分原因。我更新了问题以反映这一点。