提升Java字符串编码解码性能的技巧

简介: 在一些性能极致要求的场景,我们需要对JDK String的内部实现做不通的实现,提升字符串的编码解码性能。

FASTJSON2提升Java字符串编码解码性能的技巧


1. 常见字符串编码


常见的字符串编码有:


  • LATIN1 只能保存ASCII字符,又称ISO-8859-1。
  • UTF-8 变长字节编码,一个字符需要使用1个、2个或者3个byte表示。由于中文通常需要3个字节表示,中文场景UTF-8编码通常需要更多的空间,替代的方案是GBK/GB2312/GB18030。
  • UTF-16 2个字节,一个字符需要使用2个byte表示,又称UCS-2 (2-byte Universal Character Set)。根据大小端的区分,UTF-16有两种形式,UTF-16BE和UTF-16LE,缺省UTF-16指UTF-16BE。Java语言中的char是UTF-16LE编码。
  • GB18030 变长字节编码,一个字符需要使用1个、2个或者3个byte表示。类似UTF8,中文只需要2个字符,表示中文更省字节大小,缺点是在国际上不通用。

编码

LATIN1

UTF8

UTF16

GB18030

长度

定长为1

变长1/2/3

定长2

变长1/2/3

计算速度

英文存储空间

中文存储空间

典型场景

存储常用编码

计算常用编码

中文存储


为了计算方便,内存中字符串通常使用等宽字符,Java语言中char和.NET中的char都是使用UTF-16。早期Windows-NT只支持UTF-16。


2. 编码转换性能


UTF-16和UTF-8之间转换比较复杂,通常性能较差。



如下是一个将UTF-16转换为UTF-8编码的实现,可以看出算法比较复杂,所以性能较差,这个操作也无法使用vector API做优化。


关于Vector API 参考链接 : http://openjdk.java.net/jeps/0


staticintencodeUTF8(char[] utf16, intoff, intlen, byte[] dest, intdp) {
intsl=off+len, last_offset=sl-1;
while (off<sl) {
charc=utf16[off++];
if (c<0x80) {
// Have at most seven bitsdest[dp++] = (byte) c;
        } elseif (c<0x800) {
// 2 dest, 11 bitsdest[dp++] = (byte) (0xc0| (c>>6));
dest[dp++] = (byte) (0x80| (c&0x3f));
        } elseif (c>='\uD800'&&c<'\uE000') {
intuc;
if (c<'\uDC00') {
if (off>last_offset) {
dest[dp++] = (byte) '?';
returndp;
                }
chard=utf16[off];
if (d>='\uDC00'&&d<'\uE000') {
uc= (c<<10) +d+0xfca02400;
                } else {
thrownewRuntimeException("encodeUTF8 error", newMalformedInputException(1));
                }
            } else {
uc=c;
            }
dest[dp++] = (byte) (0xf0| ((uc>>18)));
dest[dp++] = (byte) (0x80| ((uc>>12) &0x3f));
dest[dp++] = (byte) (0x80| ((uc>>6) &0x3f));
dest[dp++] = (byte) (0x80| (uc&0x3f));
off++; // 2 utf16        } else {
// 3 dest, 16 bitsdest[dp++] = (byte) (0xe0| ((c>>12)));
dest[dp++] = (byte) (0x80| ((c>>6) &0x3f));
dest[dp++] = (byte) (0x80| (c&0x3f));
        }
    }
returndp;
}


相关代码地址: https://github.com/alibaba/fastjson2/blob/2.0.3/core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java


由于Java中char是UTF-16LE编码,如果需要将char[]转换为UTF-16LE编码的byte[]时,可以使用sun.misc.Unsafe#copyMemory方法快速拷贝。比如:


staticintwriteUtf16LE(char[] chars, intoff, intlen, byte[] dest, finalintdp) {
UNSAFE.copyMemory(chars            , CHAR_ARRAY_BASE_OFFSET+off*2            , dest            , BYTE_ARRAY_BASE_OFFSET+dp            , len*2    );
dp+=len*2;
returndp;
}


3. Java String的编码


不同版本的JDK String的实现不一样,从而导致有不同的性能表现。char是UTF-16编码,但String在JDK 9之后内部可以有LATIN1编码。


3.1. JDK 6之前的String实现


staticclassString {
finalchar[] value;
finalintoffset;
finalintcount;
}


在Java 6之前,String.subString方法产生的String对象和原来String对象共用一个char[] value,这会导致subString方法返回的String的char[]被引用而无法被GC回收。于是使得很多库都会针对JDK 6及以下版本避免使用subString方法。


3.2. JDK 7/8的String实现


staticclassString {
finalchar[] value;
}


JDK 7之后,字符串去掉了offset和count字段,value.length就是原来的count。这避免了subString引用大char[]的问题,优化也更容易,从而JDK7/8中的String操作性能比Java 6有较大提升。


3.3. JDK 9/10/11的实现


staticclassString {
finalbytecode;
finalbyte[] value;
staticfinalbyteLATIN1=0;
staticfinalbyteUTF16=1;
}


JDK 9之后,value类型从char[]变成byte[],增加了一个字段code,如果字符全部是ASCII字符,使用value使用LATIN编码;如果存在任何一个非ASCII字符,则用UTF16编码。这种混合编码的方式,使得英文场景占更少的内存。缺点是导致Java 9的String API性能可能不如JDK 8,特别是传入char[]构造字符串,会被做压缩为latin编码的byte[],有些场景会下降10%。


4. 快速构造字符串的方法


为了实现字符串是不可变特性,构造字符串的时候,会有拷贝的过程,如果要提升构造字符串的开销,就要避免这样的拷贝。


比如如下是JDK8的String的一个构造函数的实现


publicfinalclassString {
publicString(charvalue[]) {
this.value=Arrays.copyOf(value, value.length);
    }
}


在JDK8中,有一个构造函数是不做拷贝的,但这个方法不是public,需要用一个技巧实现MethodHandles.Lookup & LambdaMetafactory绑定反射来调用,文章后面有介绍这个技巧的代码。


publicfinalclassString {
String(char[] value, booleanshare) {
// assert share : "unshared not supported";this.value=value;
    }
}


快速构造字符的方法有三种:


  1. 使用MethodHandles.Lookup & LambdaMetafactory绑定反射
  2. 使用JavaLangAccess的相关方法
  3. 使用Unsafe直接构造


这三种方法,1和2性能差不多,3比1和2略慢,但都比直接new字符串要快得多。JDK8使用JMH测试的数据如下


BenchmarkModeCntScoreErrorUnitsStringCreateBenchmark.invokethrpt5784869.350±1936.754ops/msStringCreateBenchmark.langAccessthrpt5784029.186±2734.300ops/msStringCreateBenchmark.unsafethrpt5761176.319±11914.549ops/msStringCreateBenchmark.newStringthrpt5140883.533±2217.773ops/ms


在JDK 9之后,对全部是ASCII字符的场景,直接构造能达到更好的效果。


4.1 基于MethodHandles.Lookup & LambdaMetafactory绑定反射的快速构造字符串的方法



4.1.1 JDK8快速构造字符串


MethodHandles.Lookup & LambdaMetafactory要绑定非public的方法,需要特别构造一个TRUSTED的MethodHandles。


staticBiFunction<char[], Boolean, String>getStringCreatorJDK8() throwsThrowable {
Constructor<MethodHandles.Lookup>constructor=MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
MethodHandleslookup=constructor.newInstance(
String.class             , -1// Lookup.TRUSTED        );
MethodHandles.Lookupcaller=lookup.in(String.class);
MethodHandlehandle=caller.findConstructor(
String.class, MethodType.methodType(void.class, char[].class, boolean.class)
    );
CallSitecallSite=LambdaMetafactory.metafactory(
caller            , "apply"            , MethodType.methodType(BiFunction.class)
            , handle.type().generic()
            , handle            , handle.type()
    );
return (BiFunction) callSite.getTarget().invokeExact();
}
if (JDKUtils.JVM_VERSION==8) {
BiFunction<char[], Boolean, String>stringCreator=JDKUtils.getStringCreatorJDK8();
char[] chars=newchar[]{'a', 'b', 'c'};
Stringapply=stringCreator.apply(chars, Boolean.TRUE);
System.out.println(apply);
}


4.1.2 JDK 11快速构造字符串的方法

staticToIntFunction<String>getStringCode11() throwsThrowable {
Constructor<MethodHandles.Lookup>constructor=MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
MethodHandles.Lookuplookup=constructor.newInstance(
String.class            , -1// Lookup.TRUSTED    );
MethodHandles.Lookupcaller=lookup.in(String.class);
MethodHandlehandle=caller.findVirtual(
String.class, "coder", MethodType.methodType(byte.class)
    );
CallSitecallSite=LambdaMetafactory.metafactory(
caller            , "applyAsInt"            , MethodType.methodType(ToIntFunction.class)
            , MethodType.methodType(int.class, Object.class)
            , handle            , handle.type()
    );
return (ToIntFunction<String>) callSite.getTarget().invokeExact();
}
if (JDKUtils.JVM_VERSION==11) {
Function<byte[], String>stringCreator=JDKUtils.getStringCreatorJDK11();
byte[] bytes=newbyte[]{'a', 'b', 'c'};
Stringapply=stringCreator.apply(bytes);
assertEquals("abc", apply);
}


4.1.3 JDK 17快速构造字符串的方法


在JDK 17中,MethodHandles.Lookup使用Reflection.registerFieldsToFilter对lookupClass和allowedModes做了保护,网上搜索到的通过修改allowedModes的办法是不可用的。


在JDK 17中,要通过配置JVM启动参数才能使用MethodHandlers。如下:


--add-opens java.base/java.lang.invoke=ALL-UNNAMED
staticBiFunction<byte[], Charset, String>getStringCreatorJDK17() throwsThrowable {
Constructor<MethodHandles.Lookup>constructor=MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, Class.class, int.class);
constructor.setAccessible(true);
MethodHandles.Lookuplookup=constructor.newInstance(
String.class            , null            , -1// Lookup.TRUSTED    );
MethodHandles.Lookupcaller=lookup.in(String.class);
MethodHandlehandle=caller.findStatic(
String.class, "newStringNoRepl1", MethodType.methodType(String.class, byte[].class, Charset.class)
    );
CallSitecallSite=LambdaMetafactory.metafactory(
caller            , "apply"            , MethodType.methodType(BiFunction.class)
            , handle.type().generic()
            , handle            , handle.type()
    );
return (BiFunction<byte[], Charset, String>) callSite.getTarget().invokeExact();
}
if (JDKUtils.JVM_VERSION==17) {
BiFunction<byte[], Charset, String>stringCreator=JDKUtils.getStringCreatorJDK17();
byte[] bytes=newbyte[]{'a', 'b', 'c'};
Stringapply=stringCreator.apply(bytes, StandardCharsets.US_ASCII);
assertEquals("abc", apply);
}


4.2 基于JavaLangAccess快速构造


通过SharedSecrets提供的JavaLangAccess,也可以不拷贝构造字符串,但是这个比较麻烦,JDK 8/11/17的API都不一样,不同的JDK所在包名的方法都有所不同,对一套代码兼容不同的JDK版本不方便,不建议使用。


JavaLangAccessjavaLangAccess=SharedSecrets.getJavaLangAccess();
javaLangAccess.newStringNoRepl(b, StandardCharsets.US_ASCII);


4.3 基于Unsafe实现快速构造字符串


staticfinalUnsafeUNSAFE;
static {
Unsafeunsafe=null;
try {
FieldtheUnsafeField=Unsafe.class.getDeclaredField("theUnsafe");
theUnsafeField.setAccessible(true);
unsafe= (Unsafe) theUnsafeField.get(null);
    } catch (Throwableignored) {}
UNSAFE=unsafe;
}
////////////////////////////////////////////Objectstr=UNSAFE.allocateInstance(String.class);
UNSAFE.putObject(str, valueOffset, chars);


注意:在JDK 9之后,实现是不同,比如:


Objectstr=UNSAFE.allocateInstance(String.class);
UNSAFE.putByte(str, coderOffset, (byte) 0);
UNSAFE.putObject(str, valueOffset, (byte[]) bytes);


4.4 快速构建字符串的技巧应用:


如下的方法格式化日期为字符串,性能就会非常好。

staticBiFunction<byte[], Charset, String>stringCreatorJDK17=null;
staticFunction<byte[], String>stringCreatorJDK11=null;
staticBiFunction<char[], Boolean, String>stringCreatorJDK8=null;
publicStringformatYYYYMMDD(Calendarcalendar) throwsThrowable {
intyear=calendar.get(Calendar.YEAR);
intmonth=calendar.get(Calendar.MONTH) +1;
intdayOfMonth=calendar.get(Calendar.DAY_OF_MONTH);
bytey0= (byte) (year/1000+'0');
bytey1= (byte) ((year/100) %10+'0');
bytey2= (byte) ((year/10) %10+'0');
bytey3= (byte) (year%10+'0');
bytem0= (byte) (month/10+'0');
bytem1= (byte) (month%10+'0');
byted0= (byte) (dayOfMonth/10+'0');
byted1= (byte) (dayOfMonth%10+'0');
if (JDKUtils.JVM_VERSION>=9) {
byte[] bytes=newbyte[]{y0, y1, y2, y3, m0, m1, d0, d1};
if (JDKUtils.JVM_VERSION==17) {
if (stringCreatorJDK17==null) {
stringCreatorJDK17=JDKUtils.getStringCreatorJDK17();
            }
returnstringCreatorJDK17.apply(bytes, StandardCharsets.US_ASCII);
        }
if (JDKUtils.JVM_VERSION<=11) {
if (stringCreatorJDK11==null) {
stringCreatorJDK11=JDKUtils.getStringCreatorJDK11();
            }
returnstringCreatorJDK11.apply(bytes);
        }
returnnewString(bytes, StandardCharsets.US_ASCII);
    }
char[] chars=newchar[]{
            (char) y0,
            (char) y1,
            (char) y2,
            (char) y3,
            (char) m0,
            (char) m1,
            (char) d0,
            (char) d1    };
if (JDKUtils.JVM_VERSION==8) {
if (stringCreatorJDK8==null) {
stringCreatorJDK8=JDKUtils.getStringCreatorJDK8();
        }
returnstringCreatorJDK8.apply(chars, true);
    }
returnnewString(chars);
}



5. 快速遍历字符串的办法


无论JDK什么版本,String.charAt都是一个较大的开销,JIT的优化效果并不好,无法消除参数index范围检测的开销,不如直接操作String里面的value数组。


publicfinalclassString {
privatefinalcharvalue[];
publiccharcharAt(intindex) {
if ((index<0) || (index>=value.length)) {
thrownewStringIndexOutOfBoundsException(index);
        }
returnvalue[index];
    }
}


在JDK 9之后的版本,charAt开销更大


publicfinalclassString {
privatefinalbyte[] value;
privatefinalbytecoder;
publiccharcharAt(intindex) {
if (isLatin1()) {
returnStringLatin1.charAt(value, index);
        } else {
returnStringUTF16.charAt(value, index);
        }
    }
}


5.1 获取String.value的方法


获取String.value的方法有如下:


  1. 使用Field反射
  2. 使用Unsafe


Unsafe和Field反射在JDK 8 JMH的比较数据如下:


BenchmarkModeCntScoreErrorUnitsStringGetValueBenchmark.reflectthrpt5438374.685±1032.028ops/msStringGetValueBenchmark.unsafethrpt51302654.150±59169.706ops/ms

5.1.1 使用反射获取String.value


staticFieldvalueField;
static {
try {
valueField=String.class.getDeclaredField("value");
valueField.setAccessible(true);
    } catch (NoSuchFieldExceptionignored) {}
}
////////////////////////////////////////////char[] chars= (char[]) valueField.get(str);


5.1.2 使用Unsafe获取String.value


staticlongvalueFieldOffset;
static {
try {
FieldvalueField=String.class.getDeclaredField("value");
valueFieldOffset=UNSAFE.objectFieldOffset(valueField);
    } catch (NoSuchFieldExceptionignored) {}
}
////////////////////////////////////////////char[] chars= (char[]) UNSAFE.getObject(str, valueFieldOffset);
staticlongvalueFieldOffset;
staticlongcoderFieldOffset;
static {
try {
FieldvalueField=String.class.getDeclaredField("value");
valueFieldOffset=UNSAFE.objectFieldOffset(valueField);
FieldcoderField=String.class.getDeclaredField("coder");
coderFieldOffset=UNSAFE.objectFieldOffset(coderField);
    } catch (NoSuchFieldExceptionignored) {}
}
////////////////////////////////////////////bytecoder=UNSAFE.getObject(str, coderFieldOffset);
byte[] bytes= (byte[]) UNSAFE.getObject(str, valueFieldOffset);


6. 更快的encodeUTF8方法


当能直接获取到String.value时,就可以直接对其做encodeUTF8操作,会比String.getBytes(StandardCharsets.UTF_8)性能很多。


6.1 JDK8高性能encodeUTF8的方法


staticintencodeUTF8(char[] src, intoffset, intlen, byte[] dst, intdp) {
intsl=offset+len;
intdlASCII=dp+Math.min(len, dst.length);
// ASCII only optimized loopwhile (dp<dlASCII&&src[offset] <'\u0080') {
dst[dp++] = (byte) src[offset++];
    }
while (offset<sl) {
charc=src[offset++];
if (c<0x80) {
// Have at most seven bitsdst[dp++] = (byte) c;
        } elseif (c<0x800) {
// 2 bytes, 11 bitsdst[dp++] = (byte) (0xc0| (c>>6));
dst[dp++] = (byte) (0x80| (c&0x3f));
        } elseif (c>='\uD800'&&c< ('\uDFFF'+1)) { //Character.isSurrogate(c) but 1.7finalintuc;
intip=offset-1;
if (c>='\uD800'&&c< ('\uDBFF'+1)) { // Character.isHighSurrogate(c)if (sl-ip<2) {
uc=-1;
                } else {
chard=src[ip+1];
// d >= '\uDC00' && d < ('\uDFFF' + 1)if (d>='\uDC00'&&d< ('\uDFFF'+1)) { // Character.isLowSurrogate(d)uc= ((c<<10) +d) + (0x010000- ('\uD800'<<10) -'\uDC00'); // Character.toCodePoint(c, d)                    } else {
dst[dp++] = (byte) '?';
continue;
                    }
                }
            } else {
//if (c>='\uDC00'&&c< ('\uDFFF'+1)) { // Character.isLowSurrogate(c)dst[dp++] = (byte) '?';
continue;
                } else {
uc=c;
                }
            }
if (uc<0) {
dst[dp++] = (byte) '?';
            } else {
dst[dp++] = (byte) (0xf0| ((uc>>18)));
dst[dp++] = (byte) (0x80| ((uc>>12) &0x3f));
dst[dp++] = (byte) (0x80| ((uc>>6) &0x3f));
dst[dp++] = (byte) (0x80| (uc&0x3f));
offset++; // 2 chars            }
        } else {
// 3 bytes, 16 bitsdst[dp++] = (byte) (0xe0| ((c>>12)));
dst[dp++] = (byte) (0x80| ((c>>6) &0x3f));
dst[dp++] = (byte) (0x80| (c&0x3f));
        }
    }
returndp;
}


  • 使用encodeUTF8方法举例
char[] chars=UNSAFE.getObject(str, valueFieldOffset);
// ensureCapacity(chars.length * 3)byte[] bytes= ...; // intbytesLength=IOUtils.encodeUTF8(chars, 0, chars.length, bytes, bytesOffset);


这样encodeUTF8操作,不会有多余的arrayCopy操作,性能会得到提升


6.1.1 性能测试比较


  • 测试代码


publicclassEncodeUTF8Benchmark {
staticStringSTR="01234567890ABCDEFGHIJKLMNOPQRSTUVWZYZabcdefghijklmnopqrstuvwzyz一二三四五六七八九十";
staticbyte[] out;
staticlongvalueFieldOffset;
static {
out=newbyte[STR.length() *3];
try {
FieldvalueField=String.class.getDeclaredField("value");
valueFieldOffset=UnsafeUtils.UNSAFE.objectFieldOffset(valueField);
        } catch (NoSuchFieldExceptione) {
e.printStackTrace();
        }
    }
@BenchmarkpublicvoidunsafeEncodeUTF8() throwsException {
char[] chars= (char[]) UnsafeUtils.UNSAFE.getObject(STR, valueFieldOffset);
intlen=IOUtils.encodeUTF8(chars, 0, chars.length, out, 0);
    }
@BenchmarkpublicvoidgetBytesUTF8() throwsException {
byte[] bytes=STR.getBytes(StandardCharsets.UTF_8);
System.arraycopy(bytes, 0, out, 0, bytes.length);
    }
publicstaticvoidmain(String[] args) throwsRunnerException {
Optionsoptions=newOptionsBuilder()
                .include(EncodeUTF8Benchmark.class.getName())
                .mode(Mode.Throughput)
                .timeUnit(TimeUnit.MILLISECONDS)
                .forks(1)
                .build();
newRunner(options).run();
    }
}


  • 测试结果


EncodeUTF8Benchmark.getBytesUTF8thrpt520690.960±5431.442ops/msEncodeUTF8Benchmark.unsafeEncodeUTF8thrpt534508.606±55.510ops/ms


从结果来看,通过unsafe + 直接调用encodeUTF8方法, 编码的所需要开销是newStringUTF8的58%


6.2 JDK9/11/17高性能encodeUTF8的方法


publicstaticintencodeUTF8(byte[] src, intoffset, intlen, byte[] dst, intdp) {
intsl=offset+len;
while (offset<sl) {
byteb0=src[offset++];
byteb1=src[offset++];
if (b1==0&&b0>=0) {
dst[dp++] =b0;
        } else {
charc= (char)(((b0&0xff) <<0) | ((b1&0xff) <<8));
if (c<0x800) {
// 2 bytes, 11 bitsdst[dp++] = (byte) (0xc0| (c>>6));
dst[dp++] = (byte) (0x80| (c&0x3f));
            } elseif (c>='\uD800'&&c< ('\uDFFF'+1)) { //Character.isSurrogate(c) but 1.7finalintuc;
intip=offset-1;
if (c>='\uD800'&&c< ('\uDBFF'+1)) { // Character.isHighSurrogate(c)if (sl-ip<2) {
uc=-1;
                    } else {
b0=src[ip+1];
b1=src[ip+2];
chard= (char) (((b0&0xff) <<0) | ((b1&0xff) <<8));
// d >= '\uDC00' && d < ('\uDFFF' + 1)if (d>='\uDC00'&&d< ('\uDFFF'+1)) { // Character.isLowSurrogate(d)uc= ((c<<10) +d) + (0x010000- ('\uD800'<<10) -'\uDC00'); // Character.toCodePoint(c, d)                        } else {
return-1;
                        }
                    }
                } else {
//if (c>='\uDC00'&&c< ('\uDFFF'+1)) { // Character.isLowSurrogate(c)return-1;
                    } else {
uc=c;
                    }
                }
if (uc<0) {
dst[dp++] = (byte) '?';
                } else {
dst[dp++] = (byte) (0xf0| ((uc>>18)));
dst[dp++] = (byte) (0x80| ((uc>>12) &0x3f));
dst[dp++] = (byte) (0x80| ((uc>>6) &0x3f));
dst[dp++] = (byte) (0x80| (uc&0x3f));
offset++; // 2 chars                }
            } else {
// 3 bytes, 16 bitsdst[dp++] = (byte) (0xe0| ((c>>12)));
dst[dp++] = (byte) (0x80| ((c>>6) &0x3f));
dst[dp++] = (byte) (0x80| (c&0x3f));
            }
        }
    }
returndp;
}


  • 使用encodeUTF8方法举例


bytecoder=UNSAFE.getObject(str, coderFieldOffset);
byte[] value=UNSAFE.getObject(str, valueFieldOffset);
if (coder==0) {
// ascii arraycopy} else {
// ensureCapacity(chars.length * 3)byte[] bytes= ...; // intbytesLength=IOUtils.encodeUTF8(value, 0, value.length, bytes, bytesOffset);
}


这样encodeUTF8操作,不会有多余的arrayCopy操作,性能会得到提升


7. 重要提醒


上面这些技巧都不是给新手使用的,使用不当会容易导致BUG,如果你没彻底搞懂,就不要用!

目录
相关文章
|
12天前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
43 4
|
11天前
|
缓存 算法 Java
Java 实现的局域网管控软件的性能调优
局域网管控软件在企业网络管理中至关重要,但随着网络规模扩大和功能需求增加,其性能可能受影响。文章分析了数据处理效率低下、网络通信延迟和资源占用过高等性能瓶颈,并提出了使用缓存、优化算法、NIO库及合理管理线程池等调优措施,最终通过性能测试验证了优化效果,显著提升了软件性能。
28 1
|
8天前
|
Java
Java实现随机生成某个省某个市的身份证号?如何编码?
【10月更文挑战第18天】Java实现随机生成某个省某个市的身份证号?如何编码?
40 5
|
12天前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
41 2
|
2天前
|
存储 安全 Java
Java零基础-字符串详解
【10月更文挑战第18天】Java零基础教学篇,手把手实践教学!
87 60
|
2天前
|
Java 数据库连接 数据库
优化之路:Java连接池技术助力数据库性能飞跃
在Java应用开发中,数据库操作常成为性能瓶颈。频繁的数据库连接建立和断开增加了系统开销,导致性能下降。本文通过问题解答形式,深入探讨Java连接池技术如何通过复用数据库连接,显著减少连接开销,提升系统性能。文章详细介绍了连接池的优势、选择标准、使用方法及优化策略,帮助开发者实现数据库性能的飞跃。
14 4
|
7天前
|
存储 缓存 算法
提高 Java 数组性能的方法
【10月更文挑战第19天】深入探讨了提高 Java 数组性能的多种方法。通过合理运用这些策略,我们可以在处理数组时获得更好的性能表现,提升程序的运行效率。
13 2
|
19天前
|
Java 数据库
案例一:去掉数据库某列中的所有英文,利用java正则表达式去做,核心:去掉字符串中的英文
这篇文章介绍了如何使用Java正则表达式从数据库某列中去除所有英文字符。
33 15
|
存储 设计模式 IDE
阿里Java编码手册实战详解-OOP规约
阿里Java编码手册实战详解-OOP规约
130 0
|
存储 安全 Java
阿里Java编码手册实战详解-集合处理篇
阿里Java编码手册实战详解-集合处理篇
121 0