san*_*lto 6 java architecture string
你有没有想过这种变化对Java编程语言的影响?
String类被设想为一个不可变类(并且这个决定是故意考虑的).但字符串连接真的很慢,我自己对它进行了基准测试.所以StringBuffer诞生了.非常好的课程,同步和非常快.但有些人对某些同步块的性能成本不满意,并引入了StringBuilder.
但是,当使用String来连接不太多的对象时,类的不变性使其成为实现线程安全的一种非常自然的方式.当我们想要管理多个字符串时,我可以理解StringBuffer的使用.但是,这是我的第一个问题:
例如,如果您想要追加10个或更少的字符串,那么您是否会在执行时间内将简单性换成几毫秒?
我也对StringBuilder进行了基准测试.它比StringBuffer更有效(仅提高10%).但是,如果在您的单线程程序中使用StringBuilder,如果您有时想要将设计更改为使用多个线程,会发生什么?你必须改变StringBuilder的每个实例,如果你忘记了一个,你将会产生一些奇怪的效果(考虑到可能出现的竞争条件).
在这种情况下,您会在几小时的调试中交换性能吗?
好的,就是这样.除了简单的问题(StringBuffer比"+"和线程安全更有效,而StringBuilder比StringBuffer更快但没有线程安全)我想知道何时使用它们.
(重要:我知道它们之间的差异;这是与平台架构和一些设计决策相关的问题.)
只是你的"StringBuilders和线程"的评论的话:即使是在多线程程序,这是非常罕见的希望建立在多个线程的字符串.通常,每个线程都有一些数据集并从中创建一个字符串,通常是将多个字符串连接在一起.然后他们会将其转换StringBuilder为字符串,并且可以在线程之间安全地共享该字符串.
我不认为我曾经见过由于StringBuilder线程之间共享而导致的错误.
我个人希望StringBuffer不存在 - 它是在Java的"让我们同步一切"阶段,导致Vector并且Hashtable几乎已经被Java 2中的未同步ArrayList和HashMap类废弃了.它只需要花费一点时间来实现非同步的等效StringBuffer到了.
所以基本上:
StringBuilder来执行操作,通常在短期内StringBuffer除非你真的真的需要它,否则应该避免- 就像我说的那样,我记不起曾经有过这样的情况,StringBuffer而不是StringBuilder当两者都可用时.StringBuffer在Java 1.0中; 它不是对缓慢或不变性的任何反应.它也不比字符串连接更快或更好; 实际上,Java编译器编译
String s1 = s2 + s3;
Run Code Online (Sandbox Code Playgroud)
变成类似的东西
String s1 = new StringBuilder(s2).append(s3).toString();
Run Code Online (Sandbox Code Playgroud)
如果您不相信我,请使用反汇编程序(例如javap -c)自行尝试.
关于"StringBuffer比串联更快"的事情是指 重复连接.在这种情况下,显式创建yoir自己的StringBuffer并重复使用它比使编译器创建其中许多更好.
正如你所说,StringBuilder是出于性能原因在Java 5中引入的.它有意义的原因是StringBuffer/Builder实际上永远不会在创建它们的方法之外共享:99%的使用类似于上面的内容,它们被创建,用于将几个字符串附加在一起,然后丢弃.
如今,StringBuffer和Builder都是无用的(从性能的角度来看)。我解释了原因:
StringBuilder应该比StringBuffer快,但是任何精明的JVM都可以优化同步。因此,引入它时,它是一个很大的错过(和不小的打击)。
StringBuffer在创建String时不用于复制char [](非共享变量);但是,这是问题的主要根源,包括为小字符串泄漏了巨大的char []。在1.5中,他们决定每次都必须出现char []的副本,并且实际上使StringBuffer无效(在那里进行同步以确保没有线程游戏可以欺骗String)。尽管可以节省内存,但最终可以帮助GC(除了明显减少的占用空间)之外,通常char []是消耗内存的对象的前三名。
String.concat过去是而且现在仍然是连接2个字符串的最快方法(仅2个...或者可能是3个)。请记住,它不会执行char []的额外副本。
回到无用的部分,现在任何第三方代码都可以实现与StringBuilder相同的性能。即使在java1.1中,我也曾经有一个类名AsycnStringBuffer,该类名与StringBuilder现在所做的完全相同,但是它仍然比StringBuilder分配更大的char []。默认情况下,两个StrinBuffer / StringBuilder都针对小字符串进行了优化,您可以看到c-tor
StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
Run Code Online (Sandbox Code Playgroud)
因此,如果第二个字符串长于16个字符,它将获得基础char []的另一个副本。太酷了。
这可能是尝试将StringBuilder / Buffer和char []都安装到32位OS上的同一缓存行(在x86上)的副作用……但是我不确定。
至于调试时间等方面的评论。请使用您的判断力,除暗示以外,我个人不记得有任何关于字符串操作的问题。JDO impl的sql生成器的类似绳索的结构。
编辑:下面我说明了Java设计人员没有做些什么来使String操作更快。请注意,该类旨在用于java.lang包,并且只能通过将其添加到bootstrap classpath中来放置。但是,即使不放在那儿(区别是一行代码!),它仍然比StringBuilder快,令人震惊吗?该类将使string1 + string2 + ...比使用StringBuilder更好,但是...
package java.lang;
public class FastConcat {
public static String concat(String s1, String s2){
s1=String.valueOf(s1);//null checks
s2=String.valueOf(s2);
return s1.concat(s2);
}
public static String concat(String s1, String s2, String s3){
s1=String.valueOf(s1);//null checks
s2=String.valueOf(s2);
s3=String.valueOf(s3);
int len = s1.length()+s2.length()+s3.length();
char[] c = new char[len];
int idx=0;
idx = copy(s1, c, idx);
idx = copy(s2, c, idx);
idx = copy(s3, c, idx);
return newString(c);
}
public static String concat(String s1, String s2, String s3, String s4){
s1=String.valueOf(s1);//null checks
s2=String.valueOf(s2);
s3=String.valueOf(s3);
s4=String.valueOf(s4);
int len = s1.length()+s2.length()+s3.length()+s4.length();
char[] c = new char[len];
int idx=0;
idx = copy(s1, c, idx);
idx = copy(s2, c, idx);
idx = copy(s3, c, idx);
idx = copy(s4, c, idx);
return newString(c);
}
private static int copy(String s, char[] c, int idx){
s.getChars(c, idx);
return idx+s.length();
}
private static String newString(char[] c){
return new String(0, c.length, c);
//return String.copyValueOf(c);//if not in java.lang
}
}
Run Code Online (Sandbox Code Playgroud)