StringBuilderの高パフォーマンスシーンでの正しい使い方


単純な使用例
        List assetIp = buildIpLists();

        StringBuilder ips = new StringBuilder(128 + assetIp.size() * 15);
        for (Integer ip : assetIp) {
            if ( ips.length()>0 ){
                ips.append(",");
            }
            ips.append(AddressUtil.intToIp(ip));
        }

StringBuilderについては、普通の学生は簡単に覚えているだけで、文字列のつづりはStringBuilderを使い、+を使わないで、StringBufferを使わないで、それから性能が一番いいです.本当ですか.
一部の学生は、似て非なる3つの経験を聞いたことがあります.
1.Javaコンパイル最適化後+StringBuilderの効果と同じ;
2.StringBuilderはスレッドセキュリティではありません.「セキュリティ」のためにStringBufferを使用したほうがいいです.
3.ログ情報の文字列を自分でつづらないで、slf 4 jに渡してください.
 
1.初期の長さが重要で、4回言う価値がある.
StringBuilderの内部にはchar[]があり、絶えずappend()はchar[]に物を記入する過程である.
新StringBuilder()の場合char[]のデフォルト長さは16ですが、appendの17文字目を使用する場合はどうすればいいですか?
システムでarraycopy倍复制拡容!!!
これで配列コピーのコストがかかり、元のchar[]も無駄にGCされてしまう.129文字長の文字列が、16,32,64,128の4回のコピーと破棄を経て496文字の配列を申請したことが予想され、高性能シーンではほとんど我慢できません.
したがって、初期値を適切に設定することが重要です.
しかし、もし私が本当に見積もることができなかったら?もう少し見積もったほうがいいです.文字列が最後に16より大きい限り、少し無駄にしても、倍の拡張よりもいいです.
2.LiferayのStringBundlerクラス
LiferayのStringBundlerクラスは、append()のとき、char[]に急いで物を詰めるのではなく、まずString[]を持ってそれらを保存し、最後になってからすべてのStringのlengthを加えて、合理的な長さのStringBuilderを構築する別の長さ設定の考え方を提供しています.
3.しかし、やはり倍のchar[]を浪費している
浪費は最後の一歩だStringBuildertoString()
//コピーを作成し、配列return new String(value,0,count)を共有しない.
Stringのコンストラクション関数はSystemを使用します.arraycopy()は、伝達されたchar[]をコピーして安全性を保証し、物語がこのように終わると、StringBuilderのchar[]は無駄に犠牲になった.
これらのchar[]を無駄にしないためには,Unsafeのような様々なブラックテクノロジーを用いて,構造関数を迂回してStringのchar[]属性に直接値を付与する方法があるが,そうする人は少ない.
もう一つの頼りになる方法はStringBuilderを再利用することです.再利用は,最初の推定が間違っていても,数回拡張してからで十分であるため,前の長さ設定の問題も解決した.
 
4.StringBuilderの再利用
このアプローチはJDKのBigDecimalクラス(JDKコードを見ることが重要ではない)に由来し、後にNettyも同様に使用されていることが分かった.SpringSideではコードをStringBuilderHolderに抽出し、中には関数が1つしか入っていない
public StringBuilder getStringBuilder() { sb.setLength(0); return sb; }
StringBuilder.setLength()関数はcountポインタのみをリセットし、char[]は再利用を継続し、toString()の場合は現在のcountポインタもパラメータとしてStringのコンストラクション関数に渡されるので、新しいコンテンツサイズを超える古いコンテンツも転送される心配はありません.StringBuilderは完全に再利用可能であることがわかります.
同時衝突を避けるために、このHolderは一般的にThreadLocalに設定され、標準的な書き方はBigDecimalまたはStringBuilderHolderの注釈を参照してください.
しかし、Stringの長さが大きくなければ、ThreadLocalから一度値を取る代価はもっと大きいので、このThreadLocalStringBuilderを出してStringBuilderを見たら置き換えることもできません. 
5.+およびStringBuilder
String s = “hello ” + user.getName();
Javacでコンパイルされたこの文の効果は、StringBuilderを使用するのと同じですが、長さは設定されていません.
String s = new StringBuilder().append(“hello”).append(user.getName());
しかし、次のようにすれば、
String s = “hello ”;//他の文s=s+userを隔てています.getName();
文ごとに、新しいStringBuilderが生成されます.ここには2つのStringBuilderがあり、パフォーマンスが全く違います.循環体の中でs+=iであれば;もっと多くて仕方がない.
R大によると、努力しているJVMエンジニアたちは最適化の段階で、+XX:+OptimizeStringConcat(JDK 7 u 40以降デフォルトで開く)に基づいて、隣接する(中間に制御文を隔てていない)StringBuilderを1つ合成しても、努力して長さを推測する.
なので、念のため自分でStringBuilderを使い続けて長さを設定しておきましょう.
 
6.StringBufferとStringBuilder
StringBufferとStringBuilderはAbstractStringBuilderに継承されており、唯一の違いはStringBufferの関数にsynchronizedキーワードがあることです.
7.ログの文字列を永遠にslf 4 jに渡しますか?
logger.info("Hello {}", user.getName());
出力するかどうか分からないログにslf 4 jを渡すと、本当に出力が必要なときにつなぎ合わせることでコストを節約できます.
しかし、必ず出力するログについては、StringBuilderで直接接続するのが速い.slf 4 jの実現を見ると、実際には絶えずindexof("{}")、絶えずsubString()、更に絶えずStringBuilderでつなぎ合わせているだけで、銀弾はありません.
PS.slf 4 jのStringBuilderは元のMessage以外に50文字を予約していますが、可変パラメータを合わせると50文字以上になるとコピーして拡張しなければなりません.またStringBuilderも再利用されていません.
 
8.まとめ
StringBuilderのデフォルトの書き方は、129長さの文字列をつなぎ合わせて625文字の配列を申請します.したがって、高性能なシーンでは、ThreadLocalで再利用可能なStringBuilderを常に考慮する必要があります.そして再利用してから、長さを当てるゲームはもうしません.もちろん、文字列が百数十バイトしかない場合は、再利用を考慮する必要はなく、初期値を設定すればよい.
添付:
String文字列定数StringBuffer文字列変数(スレッドセキュリティ)StringBuilder文字列変数(非スレッドセキュリティ)簡単に言えば、StringタイプとStringBufferタイプの主な性能の違いは、Stringが可変のオブジェクトであることにあるので、Stringタイプを変更するたびに新しいStringオブジェクトが生成され、ポインタが新しいStringオブジェクトに向けられるのと同じであるため、コンテンツを頻繁に変更する文字列はStriを使用しないほうがよいngは、オブジェクトを生成するたびにシステムの性能に影響を与えるため、特にメモリに参照オブジェクトが多くないとJVMのGCが動作し始め、その速度はかなり遅いに違いない.StringBufferクラスを使用する場合は結果が異なり、結果のたびに新しいオブジェクトを生成するのではなく、StringBufferオブジェクト自体が操作され、オブジェクト参照が変更されます.したがって、一般的にはStringBuffer、特に文字列オブジェクトが頻繁に変更される場合を推奨します.特定の場合、Stringオブジェクトの文字列接合は、JVMによってStringBufferオブジェクトの接合として解釈されるため、Stringオブジェクトの速度はStringBufferオブジェクトよりも遅くはないが、特に以下の文字列オブジェクト生成では、String効率はStringBufferよりはるかに速い:String S 1=「This is only a」+「simple」+「test」; StringBuffer Sb = new StringBuilder(“This is only a”).append(“simple”).append(“test”); String S 1オブジェクトを生成する速度が速すぎることに驚くでしょうが、このときStringBufferは速度的に全然優位を占めていません.実はこれはJVMの1つのトリックで、JVMの目の中で、このString S 1=“This is only a”+“simple”+“test”;実はString S 1=「This is is only a simple test」です.だからもちろんあまり時間はかかりません.しかし、ここで注意しなければならないのは、もしあなたの文字列が別のStringオブジェクトから来たら、速度はそんなに速くありません.例えば、String S 2=「This is is only a」です.String S3 = “simple”; String S4 = “test”; String S1 = S2 +S3 + S4; このときJVMはきちんとしたやり方で
ほとんどの場合StringBuffer>StringStringBuffer Java.lang.StringBufferスレッドの安全な可変文字シーケンス.Stringに似た文字列バッファですが、変更できません.任意の時点で特定の文字シーケンスが含まれていますが、いくつかの方法で呼び出すことで、シーケンスの長さと内容を変更できます.文字列バッファは、複数のスレッドに安全に使用できます.これらのメソッドは、必要に応じて同期することができるため、任意の特定のインスタンス上のすべての操作は、関連する各スレッドによるメソッド呼び出し順序と一致するシリアル順序で行われるようになります.StringBuffer上の主な動作はappendメソッドとinsertメソッドであり、これらのメソッドを再ロードして任意のタイプのデータを受け入れることができる.各メソッドは、所与のデータを文字列に効率的に変換し、その文字列の文字を文字列バッファに追加または挿入することができる.appendメソッドは、これらの文字をバッファの末端に常に追加します.Insertメソッドでは、指定したポイントに文字を追加します.たとえば、zが現在のコンテンツが「start」の文字列バッファオブジェクトを参照する場合、このメソッドはz.append(「le」)を呼び出すと文字列バッファに「startle」が含まれ、z.insert(4,「le」)は文字列バッファを変更して「starlet」が含まれるようにします.ほとんどの場合、StringBuilder>StringBuffer
java.lang.StringBuilde java.lang.StringBuilder可変文字シーケンスは5.0に追加されました.これにより、StringBufferと互換性のあるAPIが提供されますが、同期は保証されません.このクラスはStringBufferの簡単な置換として設計され、文字列バッファが単一スレッドで使用される場合に使用されます(この場合は一般的です).可能であれば、ほとんどの実装ではStringBufferよりも速いため、クラスを優先することをお勧めします.両者の方法は基本的に同じです.
ターン
http://blog.csdn.net/rmn190/article/details/1492013
http://calvin1978.blogcn.com/articles/StringBuilder.html
http://www.importnew.com/24769.html