一、String和StringBuffer

String类型和StringBuffer类型的主要性能差别事实上在于String是不可变的对象,因此在每次对String类型进行改变的时候事实上都等同于生成了一个新的String对象,然后将指针指向新的String对象,所以常常改变内容的字符串最好不要用String,由于每次生成对象都会对系统性能产生影响,特别当内存中无引用对象对了以后,JVM的GC就会開始工作。那速度是一定会相当慢的。

详细说原理的话。两个字符串相加,相当于运行了例如以下操作:

Str1+str2运行了以下的过程:

StringBuffer sb1 = new StringBuffer(str1);

sb1.append(str2);

String result1 = sb1.toString();

运行到最后,我们所须要的内容仅仅有result1这一个对象,中间出现的sb1就成为了垃圾回收的目标。

此时,假设我们再加一个字符串的话……

str1+str2+str3相当于在上面的基础上又运行了

StringBuffersb2 = new StringBuffer(result1);

sb2.append(str3);

String result2 = sb2.toString();

这时。对我们实用的对象仅仅有result2一个中间生成的对象都成为了垃圾回收的目标。假设继续追加下去。又会产生若干个StringBuffer的垃圾对象和String的垃圾对象。

而假设是使用Stringbuffer类则结果就不一样了,每次结果都会对StringBuffer对象本身进行操作。而不是生成新的对象,再改变对象引用。

StringBuffersb = new StringBuffer();

sb.append(str1);

sb.append(str2);

……

sb.append(strN);

String result = sb.toString();

除了中间的一个StringBuffer对象最后会被弃掉,其它的都是有效对象,效率自然会高。

package SE.AboutString;

import java.util.Calendar;

/**
*
* <p>
* Description: 測试String和StringBuffer的效率
* </p>
* @author zhangjunshuai
* @version 1.0
* Create Date: 2014-7-7 下午5:25:57
* Project Name: UseTest
*
* <pre>
* Modification History:
* Date Author Version Description
* -----------------------------------------------------------------------------------------------------------
* LastChange: $Date:: $ $Author: $ $Rev: $
* </pre>
*
*/
public class StringMerger { public static String merge(String[] strings, String separator, boolean isSepAtTail) {
if (strings == null) {
return null;
}
if (separator == null) {
separator = "";
} String mergedString = new String();
for (int i = 0; i < strings.length - 1; i++) {
mergedString += (strings[i] + separator);
} mergedString += strings[strings.length - 1];
if (isSepAtTail) {
mergedString += separator;
} return mergedString;
} public static String bufferMerge(String[] strings, String separator, boolean isSepAtTail) {
if (strings == null) {
return null;
}
if (separator == null) {
separator = "";
} StringBuffer mergeSb = new StringBuffer();
for (int i = 0; i < strings.length - 1; i++) {
mergeSb.append(strings[i]).append(separator);
} mergeSb.append(strings[strings.length - 1]);
if (isSepAtTail) {
mergeSb.append(separator);
} return mergeSb.toString();
} public static void main(String[] args) {
// call the two methods to initialize the class and methods.
System.out.println(StringMerger.merge(new String[] {"a", "kk", "ef"}, " ^_^ ", false));
System.out.println(StringMerger.bufferMerge(new String[] {"a", "kk", "ef"}, " ^_^ ", false)); final int n = 10000;
final String sep = System.getProperty("line.separator"); // create an array of String for merging.
String[] forMerge = new String[n];
for (int i = 0; i < n; i++) {
forMerge[i] = Integer.toBinaryString(i);
} // declare two variables to store start time and end time.
long startTime = 0;
long endTime = 0; // run the test code 5 times.
for (int i = 0; i < 5; i++) {
System.out.println("==="); // get current time as start time.
startTime = Calendar.getInstance().getTimeInMillis();
// merge string by using String.
StringMerger.bufferMerge(forMerge, sep, false);
// get current time as end time.
endTime = Calendar.getInstance().getTimeInMillis();
// print out the result.
System.out.println("merge by StringBuffer start: " + startTime);
System.out.println("merge time: " + (endTime - startTime));
System.out.println("merge by StringBuffer end: " + endTime); // get current time as start time.
startTime = Calendar.getInstance().getTimeInMillis();
// merge string by using StringBuffer.
StringMerger.merge(forMerge, sep, false);
// get current time as end time.
endTime = Calendar.getInstance().getTimeInMillis();
// print out the result.
System.out.println("merge by String start: " + startTime);
System.out.println("merge time: " + (endTime - startTime));
System.out.println("merge by String end: " + endTime);
}
}
}

二、关于线程安全

线程安全就是多个线程改动同一个对象时可能产生的冲突问题。比方有一个StringBuilder对象,变量名为stringBuffer,在一个线程里运行stringBuffer.append("0")的同一时候。另外一个线程也运行相同的代码,就有可能出现无法预料的问题。

出现故障的原因是在StringBuilder的append方法中。不是仅仅有一条语句。而是由若干语句。

当进程A进入append()函数时,还有一个线程B可能在当中随意一条语句之后就进入这个函数。从而再次运行函数中第一条语句,而接下来运行线程A中即将继续运行的语句还是运行线程B中即将运行的第二句谁也说不清。

实际剖析一下,能够看到StringBuilder里面实际运行的语句例如以下(实际是运行父类的内容)

if(str == null) str = "null";

intlen = str.length();

ensureCapacityInternal(count+ len);

str.getChars(0,len, value, count);

count+= len;

returnthis;

如果StringBuilder对象中的字符串长度为10。也就是count为10。我们追加的字符串为“0”,也就是长度为1.如果当线程A运行到count+=len时候,恰好线程B的代码进入函数,而且取得运行权一直到结束,此时在线程B中的count由于加上了“0”的长度,为11.如今线程A再次開始运行,由于count的定义没有volatilekeyword,所以非常有可能线程A中的count还是之前的10,所以再次运行语句时候,让count变成11.结果命名之行了两次append()函数,count却仅仅添加了1.显然与期望逻辑不符。

由此可知StringBuffer是线程安全的可变字符序列。可将字符串缓冲区安全的用于多个线程。能够在必要时对这些方法进行同步,因此随意特定实例上的全部操作就好像是以串行顺序发生的。该顺序与所涉及的每一个线程进行的方法调用顺序一致。StringBuffer上的主要操作时append和insert方法,可重载这些方法。以接受随意的类型的数据。每一个方法都能效地将给定的数据转换成字符串。然后将该字符串的字符追加或插入到字符串缓冲区中。append方法始终将这些字符加入到缓冲区的末端。而inert方法则在指定的点加入字符。

StringBuffer是一个可变的字符序列是5.0新增的,此类提供一个与StringBuffer兼容的API。但不保证同步。该类被设计用作StringBuffer的一个简易替换,用在字符串缓冲区被单个线程使用的时候。假设可能。简易优先採用该类,由于在大多数实现中。它比StringBuffer要快。

两者的方法基本同样。

package SE.AboutString;

import java.util.Random;

public class StringBufferVsStringBuilder {
public static int demo(final Object stringJoiner, final int testCount) throws InterruptedException {
ThreadGroup group = new ThreadGroup(stringJoiner.getClass().getName() + "@" + stringJoiner.hashCode());
final Random rand = new Random(); Runnable listAppender = new Runnable() {
public void run() {
try {
Thread.sleep(rand.nextInt(2));
} catch (InterruptedException e) {
return;
}
if (stringJoiner instanceof StringBuffer) {
((StringBuffer)stringJoiner).append("0");
} else if (stringJoiner instanceof StringBuilder) {
((StringBuilder)stringJoiner).append("0");
}
}
}; for (int i = 0; i < testCount; i++) {
new Thread(group, listAppender, "InsertList-" + i).start();
} while (group.activeCount() > 0) {
Thread.sleep(10);
} return stringJoiner.toString().length();
} public static void main(String[] args) throws InterruptedException {
StringBuilder stringBuilder = new StringBuilder();
StringBuffer stringBuffer = new StringBuffer();
final int N = 10000;
for (int i = 0; i < 10; i++) {
stringBuilder.delete(0, stringBuilder.length());
stringBuffer.delete(0, stringBuffer.length());
int builderLength = demo(stringBuilder, N);
int bufferLength = demo(stringBuffer, N);
System.out.println("StringBuilder/StringBuffer: " + builderLength + "/" + bufferLength);
}
}
} // Output will be something like this:
// StringBuilder/StringBuffer: 9995/10000
// StringBuilder/StringBuffer: 9996/10000
// StringBuilder/StringBuffer: 9998/10000
// StringBuilder/StringBuffer: 9997/10000
// StringBuilder/StringBuffer: 9995/10000
// StringBuilder/StringBuffer: 9996/10000
// StringBuilder/StringBuffer: 9998/10000
// StringBuilder/StringBuffer: 9998/10000
// StringBuilder/StringBuffer: 9999/10000
// StringBuilder/StringBuffer: 9999/10000

package SE.AboutString;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random; public class ThreadSafeDemo {
public static int demo(final List list, final int testCount) throws InterruptedException {
ThreadGroup group = new ThreadGroup(list.getClass().getName() + "@" + list.hashCode());
final Random rand = new Random(); Runnable listAppender = new Runnable() {
public void run() {
try {
Thread.sleep(rand.nextInt(2));
} catch (InterruptedException e) {
return;
}
list.add("0");
}
}; for (int i = 0; i < testCount; i++) {
new Thread(group, listAppender, "InsertList-" + i).start();
} while (group.activeCount() > 0) {
Thread.sleep(10);
} return list.size();
}
public static void main(String[] args) throws InterruptedException {
List unsafeList = new ArrayList();
List safeList = Collections.synchronizedList(new ArrayList());
final int N = 10000;
for (int i = 0; i < 10; i++) {
unsafeList.clear();
safeList.clear();
int unsafeSize = demo(unsafeList, N);
int safeSize = demo(safeList, N);
System.out.println("unsafe/safe: " + unsafeSize + "/" + safeSize);
}
}
} /*unsafe/safe: 9896/10000
unsafe/safe: 9931/10000
unsafe/safe: 9940/10000
unsafe/safe: 9912/10000
unsafe/safe: 9960/10000
unsafe/safe: 9954/10000
unsafe/safe: 9960/10000
unsafe/safe: 9944/10000
unsafe/safe: 9960/10000
unsafe/safe: 9957/10000*/

參考:

http://www.zhihu.com/question/20101840

http://blog.csdn.net/rmn190/article/details/1492013

版权声明:本文博客原创文章,博客,未经同意,不得转载。

String、StringBuffer和StringBuilder的更多相关文章

  1. String,StringBuffer和StringBuilder源码解析[基于JDK6]

    最近指导几位新人,学习了一下String,StringBuffer和StringBuilder类,从反馈的结果来看,总体感觉学习的深度不够,没有读出东西.其实,JDK的源码是越读越有味的.下面总结一下 ...

  2. String,StringBuffer和StringBuilder的异同

                                                                    String,StringBuffer和StringBuilder的异同 ...

  3. String,StringBuffer与StringBuilder

    1. String,StringBuffer与StringBuilder的区别 String:存储在常量池中:是不可变的字符序列,任何对String值的改变都会引发新的String对象的生成,因此执行 ...

  4. Java String, StringBuffer和StringBuilder实例

    1- 分层继承2- 可变和不可变的概念3- String3.1- 字符串是一个非常特殊的类3.2- String 字面值 vs. String对象3.3- String的方法3.3.1- length ...

  5. String, StringBuffer and StringBuilder

    一 String 概述: String 被声明为 final,因此它不可被继承. 在 Java 8 中,String 内部使用 char 数组存储数据. public final class Stri ...

  6. String,StringBuffer和StringBuilder

    String,StringBuffer和StringBuilder分别应该在什么情况下使用? String 是Java的字符串类,其实质上也是用Char类型存储的,但是除了hash属性,其他的属性都声 ...

  7. String,StringBuffer与StringBuilder的区别??

    转自http://blog.csdn.net/rmn190/article/details/1492013 String 字符串常量 StringBuffer 字符串变量(线程安全) StringBu ...

  8. Java中String,StringBuffer与StringBuilder的差别

    String 字符串常量: StringBuffer 字符串变量〈缓冲区〉(线程安全): StringBuilder 字符串变量〈缓冲区〉(非线程安全): 简要的说, String 类型和 Strin ...

  9. JAVA String,StringBuffer与StringBuilder的区别??

    String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能 ...

  10. 转 String,StringBuffer与StringBuilder的区别??

    String 字符串常量StringBuffer 字符串变量(线程安全)StringBuilder 字符串变量(非线程安全) 简要的说, String 类型和 StringBuffer 类型的主要性能 ...

随机推荐

  1. 2)JS动态生成HTML元素的爬取

    2)JS动态生成HTML元素的爬取 import java.util.List; import org.openqa.selenium.By; import org.openqa.selenium.W ...

  2. java中的特殊字符集合

    JAVA中转义字符: 1.八进制转义序列:\ + 1到3位5数字:范围'\000'~'\377'       \0:空字符 2.Unicode转义字符:\u + 四个 十六进制数字:0~65535   ...

  3. UVA 11490 - Just Another Problem(数论)

    11490 - Just Another Problem option=com_onlinejudge&Itemid=8&page=show_problem&category= ...

  4. Cocos2d-x中父节点scale对子节点的影响

    背景:在前几天,刚接触cocos2d-x,随便找了一张图,作为一个CCSprite,而且设置了scale属性,然后在这个sprite上创建了一个CCLabelTTF,并用sprite->addC ...

  5. 黄聪:Microsoft Enterprise Library 5.0 系列教程(三) Validation Application Block (高级)

    原文:黄聪:Microsoft Enterprise Library 5.0 系列教程(三) Validation Application Block (高级) 企业库验证应用程序模块之配置文件模式: ...

  6. wamp的安装使用(转)

    这次需要记录一下我搭建web服务器的过程. 第一步,确定自己要使用的平台:这次我用的是windows2008 server版本 第二步,计划是想要纯手工的安装apache.php等.但是我们可以下载一 ...

  7. 集成框架 javaweb开发平台ssmy_m(生成代码) java struts2 mybatis spring maven jquery

    网页地址 http://blog.csdn.net/lpy3654321/article/details/31841573 项目设想,在项目开发中,我们的开发者大多数时间都在反复开发 相同的keywo ...

  8. Windows Phone开发(17):URI映射

    原文:Windows Phone开发(17):URI映射 前面在讲述导航的知识,也讲了控件,也讲了资源,样式,模板,相信大家对UI部分的内容应该有了很直观的认识了.那么今天讲什么呢?不知道大家在练习导 ...

  9. HDU 3036 Escape 网格图多人逃生 网络流||二分匹配 建图技巧

    题意: 每一个' . '有一个姑娘, E是出口,'.'是空地 , 'X' 是墙. 每秒钟每一个姑娘能够走一步(上下左右) 每秒钟每一个出口仅仅能出去一个人 给定n*m的地图, 时限T 问全部姑娘是否能 ...

  10. [置顶] android系统如何在静音模式下关闭camera拍照声音(2)

    之前写过一篇“android系统如何在静音模式下关闭camera拍照声音”的博客,今天来写他的续篇,继续探讨这个问题. 公司新需求,要求在camera应用中添加一个开关,可以进行拍照声音的关闭和开启. ...