測試clone和new方法的效率差別,首先來反面教材.
public class TestCloneAndNewMain {
public static void main(String[] args) throws CloneNotSupportedException {
TestClone original = new TestClone("1", "2", "3", "4", "5", "6", "7", "8", "9");
long l1 = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
newCopy(original);
}
long l2 = System.currentTimeMillis();
long l3 = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
original.clone();
}
long l4 = System.currentTimeMillis();
System.out.println("new " + (l2 - l1));
System.out.println("clone " + (l4 - l3));
}
public static TestClone newCopy(TestClone original) {
TestClone testClone = new TestClone();
testClone.setValue1(original.getValue1());
testClone.setValue2(original.getValue2());
testClone.setValue3(original.getValue3());
testClone.setValue4(original.getValue4());
testClone.setValue5(original.getValue5());
testClone.setValue6(original.getValue6());
testClone.setValue7(original.getValue7());
testClone.setValue8(original.getValue8());
testClone.setValue9(original.getValue9());
return testClone;
}
static class TestClone implements Cloneable {
private Integer i;
private String value1;
private String value2;
private String value3;
private String value4;
private String value5;
private String value6;
private String value7;
private String value8;
private String value9;
public TestClone() {
}
public TestClone(String value1, String value2, String value3, String value4, String value5, String value6, String value7, String value8, String value9) {
this.value1 = value1;
this.value2 = value2;
this.value3 = value3;
this.value4 = value4;
this.value5 = value5;
this.value6 = value6;
this.value7 = value7;
this.value8 = value8;
this.value9 = value9;
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public String getValue3() {
return value3;
}
public void setValue3(String value3) {
this.value3 = value3;
}
public String getValue4() {
return value4;
}
public void setValue4(String value4) {
this.value4 = value4;
}
public String getValue5() {
return value5;
}
public void setValue5(String value5) {
this.value5 = value5;
}
public String getValue6() {
return value6;
}
public void setValue6(String value6) {
this.value6 = value6;
}
public String getValue7() {
return value7;
}
public void setValue7(String value7) {
this.value7 = value7;
}
public String getValue8() {
return value8;
}
public void setValue8(String value8) {
this.value8 = value8;
}
public String getValue9() {
return value9;
}
public void setValue9(String value9) {
this.value9 = value9;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Integer getI() {
return i;
}
public void setI(Integer i) {
this.i = i;
}
}
}
結果
new 9
clone 1688
把new的方法次數X10,clone不變
結果
new 7
clone 1781
次數執行更多,時間反而降低了,超出想象.
這是真的嗎?
這是假的吧.但是這真真實實是結果
當你懷疑人生的時候,就像三體裏面的物理學家質疑基礎物理學一樣.
我給你爲什麼:
現代編譯器是十分聰明的,它們會對你的代碼進行推導分析,判定哪些代碼是無用的然後進行去除,這種行爲對微基準測試是致命的,它會使你無法準確測試出你的方法性能。JMH本身已經對這種情況做了處理,你只要記住:1.永遠不要寫void方法;2.在方法結束返回你的計算結果。有時候如果需要返回多於一個結果,可以考慮自行合併計算結果,或者使用JMH提供的BlackHole對象
那麼我現在就是要用JMH,打破三體人的智子.
結果,clone耗時更少,效率更高.
Benchmark Mode Cnt Score Error Units
TestCloneAndNew.cloneCopy avgt 2 1200260940.500 ns/op
TestCloneAndNew.newCopy avgt 2 3277323023.500 ns/op
代碼如下
@BenchmarkMode(Mode.AverageTime)//基準測試類型
@OutputTimeUnit(TimeUnit.NANOSECONDS)//基準測試結果的時間類型
@Warmup(iterations = 10)//預熱的迭代次數
//度量:iterations進行測試的輪次,time每輪進行的時長,timeUnit時長單位,batchSize批次數量
@State(Scope.Thread)
@Measurement(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1)
public class TestCloneAndNew {
public static TestClone newCopy(TestClone original) {
TestClone testClone = new TestClone();
testClone.setValue1(original.getValue1());
testClone.setValue2(original.getValue2());
testClone.setValue3(original.getValue3());
testClone.setValue4(original.getValue4());
testClone.setValue5(original.getValue5());
testClone.setValue6(original.getValue6());
testClone.setValue7(original.getValue7());
testClone.setValue8(original.getValue8());
testClone.setValue9(original.getValue9());
return testClone;
}
@Benchmark
public void newCopy() {
TestClone original = new TestClone("1", "2", "3", "4", "5", "6", "7", "8", "9");
for (int i = 0; i < 100000000; i++) {
newCopy(original);
}
}
@Benchmark
public void cloneCopy() throws CloneNotSupportedException {
TestClone original = new TestClone("1", "2", "3", "4", "5", "6", "7", "8", "9");
for (int i = 0; i < 100000000; i++) {
original.clone();
}
}
public static void main(String[] args) {
try {
Options opt = new OptionsBuilder()
.include(TestCloneAndNew.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
} catch (Exception e) {
e.printStackTrace();
}
}
static class TestClone implements Cloneable {
private Integer i;
private String value1;
private String value2;
private String value3;
private String value4;
private String value5;
private String value6;
private String value7;
private String value8;
private String value9;
public TestClone() {
}
public TestClone(String value1, String value2, String value3, String value4, String value5, String value6, String value7, String value8, String value9) {
this.value1 = value1;
this.value2 = value2;
this.value3 = value3;
this.value4 = value4;
this.value5 = value5;
this.value6 = value6;
this.value7 = value7;
this.value8 = value8;
this.value9 = value9;
}
public String getValue1() {
return value1;
}
public void setValue1(String value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
public String getValue3() {
return value3;
}
public void setValue3(String value3) {
this.value3 = value3;
}
public String getValue4() {
return value4;
}
public void setValue4(String value4) {
this.value4 = value4;
}
public String getValue5() {
return value5;
}
public void setValue5(String value5) {
this.value5 = value5;
}
public String getValue6() {
return value6;
}
public void setValue6(String value6) {
this.value6 = value6;
}
public String getValue7() {
return value7;
}
public void setValue7(String value7) {
this.value7 = value7;
}
public String getValue8() {
return value8;
}
public void setValue8(String value8) {
this.value8 = value8;
}
public String getValue9() {
return value9;
}
public void setValue9(String value9) {
this.value9 = value9;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public Integer getI() {
return i;
}
public void setI(Integer i) {
this.i = i;
}
}
}
MAVEN:
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.19</version>
<!--<scope>test</scope>-->
</dependency>