毁三观,StringBuffer与StringBuilder到底哪个更快

HallWong 2013-09-12 05:51:03
都说StringBuilder是单线程的,要比StringBuffer快,但是下面的代码,在我的机器上跑,StringBuffer的性能愣是比StringBuilder强。。。求高人解答,看看是我的测试方法不对还是什么个情况?

	public static void main(String[] args) {
insertTest();
}

public static void insertTest() {
int t = 10;
int[] times = { 10 * t, 100 * t, 1000 * t, 10000 * t, 15000 * t };
StringBuilder sbBuilder = new StringBuilder();
StringBuffer sbBuffer = new StringBuffer();
long l;
int i;
for (int time : times) {
l = System.currentTimeMillis();
for (i = 0; i < time; i++) {
stringBuilderInsert(sbBuilder, "hello world");
}
System.out.println("builder run " + time + " times insert take " + (System.currentTimeMillis() - l) + "ms");
l = System.currentTimeMillis();
for (i = 0; i < time; i++) {
stringBufferInsert(sbBuffer, "hello world");
}
System.out.println("buffer run " + time + " times insert take " + (System.currentTimeMillis() - l) + "ms");
}
}

public static StringBuilder stringBuilderInsert(StringBuilder dest, String str) {
int offset = (int) (Math.random() * dest.length());
dest.insert(offset, str);
return dest;
}

public static StringBuffer stringBufferInsert(StringBuffer dest, String str) {
int offset = (int) (Math.random() * dest.length());
dest.insert(offset, str);
return dest;
}

下面是运行的结果
...全文
1057 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
无聊找乐 2013-10-21
  • 打赏
  • 举报
回复
貌似楼主的电脑速度挺快 builder run 100 times insert take 0ms buffer run 100 times insert take 1ms builder run 1000 times insert take 2ms buffer run 1000 times insert take 1ms builder run 10000 times insert take 74ms buffer run 10000 times insert take 85ms builder run 100000 times insert take 7605ms buffer run 100000 times insert take 7636ms builder run 150000 times insert take 38561ms buffer run 150000 times insert take 39384ms
HallWong 2013-10-21
  • 打赏
  • 举报
回复
引用 16 楼 lcf 的回复:
[quote=引用 15 楼 HallWong 的回复:] [quote=引用 12 楼 lcf 的回复:] [quote=引用 11 楼 HallWong 的回复:] [quote=引用 7 楼 lcf 的回复:] 做测试有一个基本原则,就是可重复性。你用了random,就违背了这条原则,你没法重复你的实验,对于实验误差就不可能用统计学来修正,因为你每一次实验都不一样。 做Java测试有一个非常需要注意的点,就是有时候你并不知道你在测试什么。 1. 当你把两个函数放在一个地方测试的时候,前一个函数很有可能影响后一个函数的结果 2. 当你像我说的去掉了随机性,一不小心JVM就会当做你在做无用功,而把你要测试的代码直接跳过了,然后你就得到了一个很惊艳的值 3. 做测试之前一定要做预热(先让你要测试的代码跑个10000次),之后才能开始做测试 4. 做测试的时候尽量减少内存分配,如果不行,就尽可能减少内存释放,因为你无法控制GC的执行时间,而这对于微秒精度的性能测试是致命的
这位大大,如果我想测试随机插入的性能,那可不可以使用random?[/quote] 不能。 你要建立一个100,000长度(或者你希望的任何长度)的int[],预先用random算好它们的值,然后存进一个文件。然后把两个测试函数分别写在两个main里面,每次分别用两个main来测试速度,将结果写入另两个文件,然后你就可以用excel之类的工具作统计学比较了。发布实验结果的时候一定要连所有源文件,包括产生int[]的代码一起发布。这样才是比较像样的benchmark。专业的benchmark当然还要包含gc的数据,测试平台配置等一些杂项[/quote]受教了,这么做是尽可能的减小random方法产生的性能影响。[/quote] 不对。这么做是让实验公平。不然前后两次实验的数据都不一样,怎么进行公平的比较?[/quote] 哦哦,理解有误
lcf 2013-10-21
  • 打赏
  • 举报
回复
引用 15 楼 HallWong 的回复:
[quote=引用 12 楼 lcf 的回复:] [quote=引用 11 楼 HallWong 的回复:] [quote=引用 7 楼 lcf 的回复:] 做测试有一个基本原则,就是可重复性。你用了random,就违背了这条原则,你没法重复你的实验,对于实验误差就不可能用统计学来修正,因为你每一次实验都不一样。 做Java测试有一个非常需要注意的点,就是有时候你并不知道你在测试什么。 1. 当你把两个函数放在一个地方测试的时候,前一个函数很有可能影响后一个函数的结果 2. 当你像我说的去掉了随机性,一不小心JVM就会当做你在做无用功,而把你要测试的代码直接跳过了,然后你就得到了一个很惊艳的值 3. 做测试之前一定要做预热(先让你要测试的代码跑个10000次),之后才能开始做测试 4. 做测试的时候尽量减少内存分配,如果不行,就尽可能减少内存释放,因为你无法控制GC的执行时间,而这对于微秒精度的性能测试是致命的
这位大大,如果我想测试随机插入的性能,那可不可以使用random?[/quote] 不能。 你要建立一个100,000长度(或者你希望的任何长度)的int[],预先用random算好它们的值,然后存进一个文件。然后把两个测试函数分别写在两个main里面,每次分别用两个main来测试速度,将结果写入另两个文件,然后你就可以用excel之类的工具作统计学比较了。发布实验结果的时候一定要连所有源文件,包括产生int[]的代码一起发布。这样才是比较像样的benchmark。专业的benchmark当然还要包含gc的数据,测试平台配置等一些杂项[/quote]受教了,这么做是尽可能的减小random方法产生的性能影响。[/quote] 不对。这么做是让实验公平。不然前后两次实验的数据都不一样,怎么进行公平的比较?
HallWong 2013-10-21
  • 打赏
  • 举报
回复
引用 12 楼 lcf 的回复:
[quote=引用 11 楼 HallWong 的回复:] [quote=引用 7 楼 lcf 的回复:] 做测试有一个基本原则,就是可重复性。你用了random,就违背了这条原则,你没法重复你的实验,对于实验误差就不可能用统计学来修正,因为你每一次实验都不一样。 做Java测试有一个非常需要注意的点,就是有时候你并不知道你在测试什么。 1. 当你把两个函数放在一个地方测试的时候,前一个函数很有可能影响后一个函数的结果 2. 当你像我说的去掉了随机性,一不小心JVM就会当做你在做无用功,而把你要测试的代码直接跳过了,然后你就得到了一个很惊艳的值 3. 做测试之前一定要做预热(先让你要测试的代码跑个10000次),之后才能开始做测试 4. 做测试的时候尽量减少内存分配,如果不行,就尽可能减少内存释放,因为你无法控制GC的执行时间,而这对于微秒精度的性能测试是致命的
这位大大,如果我想测试随机插入的性能,那可不可以使用random?[/quote] 不能。 你要建立一个100,000长度(或者你希望的任何长度)的int[],预先用random算好它们的值,然后存进一个文件。然后把两个测试函数分别写在两个main里面,每次分别用两个main来测试速度,将结果写入另两个文件,然后你就可以用excel之类的工具作统计学比较了。发布实验结果的时候一定要连所有源文件,包括产生int[]的代码一起发布。这样才是比较像样的benchmark。专业的benchmark当然还要包含gc的数据,测试平台配置等一些杂项[/quote]受教了,这么做是尽可能的减小random方法产生的性能影响。
玄影镜心 2013-10-19
  • 打赏
  • 举报
回复
不加锁当然快
Lsheep 2013-10-18
  • 打赏
  • 举报
回复
楼上有几个同学完全没理解楼主的意思。 StringBuffer是线程安全的,所以多出一些同步判断,所以才会在单线程的情况下相对于StringBuilder要慢。在多线程的情况下就会出现错误,哪有速度可言。
lcf 2013-10-18
  • 打赏
  • 举报
回复
引用 11 楼 HallWong 的回复:
[quote=引用 7 楼 lcf 的回复:] 做测试有一个基本原则,就是可重复性。你用了random,就违背了这条原则,你没法重复你的实验,对于实验误差就不可能用统计学来修正,因为你每一次实验都不一样。 做Java测试有一个非常需要注意的点,就是有时候你并不知道你在测试什么。 1. 当你把两个函数放在一个地方测试的时候,前一个函数很有可能影响后一个函数的结果 2. 当你像我说的去掉了随机性,一不小心JVM就会当做你在做无用功,而把你要测试的代码直接跳过了,然后你就得到了一个很惊艳的值 3. 做测试之前一定要做预热(先让你要测试的代码跑个10000次),之后才能开始做测试 4. 做测试的时候尽量减少内存分配,如果不行,就尽可能减少内存释放,因为你无法控制GC的执行时间,而这对于微秒精度的性能测试是致命的
这位大大,如果我想测试随机插入的性能,那可不可以使用random?[/quote] 不能。 你要建立一个100,000长度(或者你希望的任何长度)的int[],预先用random算好它们的值,然后存进一个文件。然后把两个测试函数分别写在两个main里面,每次分别用两个main来测试速度,将结果写入另两个文件,然后你就可以用excel之类的工具作统计学比较了。发布实验结果的时候一定要连所有源文件,包括产生int[]的代码一起发布。这样才是比较像样的benchmark。专业的benchmark当然还要包含gc的数据,测试平台配置等一些杂项
HallWong 2013-10-18
  • 打赏
  • 举报
回复
引用 7 楼 lcf 的回复:
做测试有一个基本原则,就是可重复性。你用了random,就违背了这条原则,你没法重复你的实验,对于实验误差就不可能用统计学来修正,因为你每一次实验都不一样。 做Java测试有一个非常需要注意的点,就是有时候你并不知道你在测试什么。 1. 当你把两个函数放在一个地方测试的时候,前一个函数很有可能影响后一个函数的结果 2. 当你像我说的去掉了随机性,一不小心JVM就会当做你在做无用功,而把你要测试的代码直接跳过了,然后你就得到了一个很惊艳的值 3. 做测试之前一定要做预热(先让你要测试的代码跑个10000次),之后才能开始做测试 4. 做测试的时候尽量减少内存分配,如果不行,就尽可能减少内存释放,因为你无法控制GC的执行时间,而这对于微秒精度的性能测试是致命的
这位大大,如果我想测试随机插入的性能,那可不可以使用random?
HallWong 2013-10-18
  • 打赏
  • 举报
回复
好吧,我的测试方法是有问题的,因为两个测试方法是在同一个JVM里运行的,所以。。。 后来我在不同的JVM里运行这两个方法,两者的方法差不太多 我2了。。。
  • 打赏
  • 举报
回复
引用 3 楼 etnet 的回复:
StringBuilder是非线程安全的,StringBuffer是线程安全的. 两个都是继承于java.lang.AbstractStringBuilder的,最终调用的都是这个AbstractStringBuilder类里面定义的方法. StringBuilder只是少一些锁的开销而已,单个线程下能有什么区别...?
+1
txtdown0909 2013-09-12
  • 打赏
  • 举报
回复
引用 3 楼 etnet 的回复:
StringBuilder是非线程安全的,StringBuffer是线程安全的. 两个都是继承于java.lang.AbstractStringBuilder的,最终调用的都是这个AbstractStringBuilder类里面定义的方法. StringBuilder只是少一些锁的开销而已,单个线程下能有什么区别...?
+1 两个类差不多,区别主要就是线程安全与否。单线程时比较两个类没有意义,但是多线程时,因为线程安全的需要进行同步,所以效率上可以会差点。
lcf 2013-09-12
  • 打赏
  • 举报
回复
做测试有一个基本原则,就是可重复性。你用了random,就违背了这条原则,你没法重复你的实验,对于实验误差就不可能用统计学来修正,因为你每一次实验都不一样。 做Java测试有一个非常需要注意的点,就是有时候你并不知道你在测试什么。 1. 当你把两个函数放在一个地方测试的时候,前一个函数很有可能影响后一个函数的结果 2. 当你像我说的去掉了随机性,一不小心JVM就会当做你在做无用功,而把你要测试的代码直接跳过了,然后你就得到了一个很惊艳的值 3. 做测试之前一定要做预热(先让你要测试的代码跑个10000次),之后才能开始做测试 4. 做测试的时候尽量减少内存分配,如果不行,就尽可能减少内存释放,因为你无法控制GC的执行时间,而这对于微秒精度的性能测试是致命的
  • 打赏
  • 举报
回复
原来如此。。
郭梧悠 2013-09-12
  • 打赏
  • 举报
回复
循环一百万次,试试就知道了
逍遥jc 2013-09-12
  • 打赏
  • 举报
回复
在单线程下应该时间不会有太大差距才对。
etnet 2013-09-12
  • 打赏
  • 举报
回复
StringBuilder是非线程安全的,StringBuffer是线程安全的. 两个都是继承于java.lang.AbstractStringBuilder的,最终调用的都是这个AbstractStringBuilder类里面定义的方法. StringBuilder只是少一些锁的开销而已,单个线程下能有什么区别...?
kemucc 2013-09-12
  • 打赏
  • 举报
回复
单线程的?不是线程安全的区别么
healer_kx 2013-09-12
  • 打赏
  • 举报
回复
http://sxzgll.iteye.com/blog/159292 看这个吧,。。。什么叫“单线程的”,你确实需要毁三观再来。
数据集可视化效果可参见下方展示。 【数据集概况】 · 检测类别(中文):[保龄球(bowling)] · 训练集:594 张 · 验证集:75 张 · 测试集:74 张 · 总计:743 张 该数据集聚焦于室内保龄球馆场景,系统性采集了多角度、多姿态下保龄球在不同运动阶段的视觉特征,为保龄球运动过程中的球体识别与轨迹分析提供了高质量标注样本,具有明确的体育训练与智能辅助系统开发价值。... 【训练曲线与评估图】 【模型训练配置】 参数 | 值 模型 | yolo26n 训练轮数 | 100 epochs 输入尺寸 | 640x640 批次大小 | 24 优化器 | auto 初始学习率 | 0.01 训练设备 【关键指标汇总】 训练了 100 个 epoch,最终轮指标: 指标 | 数值 mAP50 | **0.9938** mAP50-95 | 0.6966 Precision | 0.9740 Recall | 0.9974 train/box_loss | 0.9113 train/cls_loss | 0.2862 val/box_loss | 1.1516 val/cls_loss | 0.3116 【训练过程分析】 100 轮训练后 mAP50 达到 0.9938,模型收敛良好。Loss 曲线前段快速下降,后段趋于平稳,val_loss 无反弹,没有明显过拟合。但 mAP50-95 为 0.6966,和 mAP50 差距 0.30,定位精度仍有优化空间。 【模型性能评估】 Precision 0.9740、Recall 0.9974,精召双高,模型对保龄球的检测能力强。 【预测效果展示】 验证集预测效果较好,检测框基本准确覆盖保龄球,置信度整体偏高。 【改进建议】 1. 丰富场景多样性:补充不同光照、背景和遮挡条件下的样本。 2. 提升输入分辨率:640 ...
PaddleOCR 与YOLO目标检测 HTTP 服务。 项目通过 PaddleOCROnnx 原生库集成 OnnxRuntime加速能力,围绕 ONNX 模型部署, 以统一接口提供图像文字识别、YOLO 目标检测和 Tensor 数据输出。 功能概览 文字识别:支持图片 Base64、multipart/form-data 上传,以及文本和 JSON 结果。 目标检测:支持 YOLO 图片检测,返回检测框 JSON 或原始 Tensor。 浏览器演示:访问服务根地址,上传图片并切换 OCR、YOLO 模式。 健康检查:通过 /health 查看服务及 OCR、YOLO 引擎初始化状态。 并发处理:通过 OCR 引擎实例池处理并发请求,可调整实例数量。 体验与调用 启动后访问: 入口 地址 浏览器演示 http://localhost:5000/ 健康检查 http://localhost:5000/health 原生依赖 Windows:优先从 runtimes/win-x64/native/ 加载原生 DLL;该目录没有 PaddleOCROnnx.dll 时,尝试从可执行文件所在目录加载。主 DLL 与对应后端依赖应放在同一原生目录中,不要将同一组依赖分散到多个目录。 Linux:原生运行时位于 runtimes/linux-x64/native/,程序使用相对于可执行文件的运行时搜索路径查找随包部署的依赖。 后端选择:CoreOCROnnx 支持 ONNX Runtime、OpenVINO、TensorRT 后端。请使用与平台、进程架构、硬件和后端匹配的一整套运行时,不要混用不同后端或版本的依赖。

62,621

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧