Quelle est la principale différence entre StringBuffer
et StringBuilder
? Existe-t-il des problèmes de performances lors de la décision?
StringBuffer
est synchronisé, StringBuilder
n'est pas.
StringBuilder
est plus rapide que StringBuffer
car ce n'est pas synchronized
.
Voici un test de référence simple:
public class Main {
public static void main(String[] args) {
int N = 77777777;
long t;
{
StringBuffer sb = new StringBuffer();
t = System.currentTimeMillis();
for (int i = N; i --> 0 ;) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
{
StringBuilder sb = new StringBuilder();
t = System.currentTimeMillis();
for (int i = N; i > 0 ; i--) {
sb.append("");
}
System.out.println(System.currentTimeMillis() - t);
}
}
}
A test donne les numéros de 2241 ms
pour StringBuffer
et 753 ms
pour StringBuilder
.
Fondamentalement, les méthodes StringBuffer
sont synchronisées alors que StringBuilder
ne le sont pas.
Les opérations sont "presque" identiques, mais l'utilisation de méthodes synchronisées dans un seul thread est excessive.
C'est à peu près à ce sujet.
Citation de API StringBuilder :
Cette classe [StringBuilder] fournit une API compatible avec StringBuffer, mais sans garantie de synchronisation . Cette classe est conçue pour être utilisée comme remplacement immédiat de StringBuffer dans les endroits où le tampon de chaîne était utilisé par un seul thread (comme c'est généralement le cas). Dans la mesure du possible, il est recommandé d'utiliser cette classe de préférence à StringBuffer, car elle sera plus rapide dans la plupart des mises en œuvre .
Donc, il a été fait pour le remplacer.
La même chose s'est produite avec Vector
et ArrayList
.
Mais avez-vous besoin de voir clairement la différence à l'aide d'un exemple?
StringBuffer ou StringBuilder
tilisez simplement StringBuilder
sauf si vous essayez réellement de partager un tampon entre les threads. StringBuilder
est le frère cadet non synchronisé (moins de charge = plus efficace) la classe StringBuffer
synchronisée d'origine.
StringBuffer
est arrivé en premier. Sun était soucieux de l'exactitude dans toutes les conditions. Ils l'ont donc synchronisé pour le rendre thread-safe au cas où.
StringBuilder
est venu plus tard. La plupart des utilisations de StringBuffer
étaient mono-thread et payaient inutilement le coût de la synchronisation.
Puisque StringBuilder
est un remplacement ) pour StringBuffer
sans synchronisation, il n'y aurait pas être des différences entre des exemples.
Si vous essayez de partager des threads, vous pouvez utiliser StringBuffer
, mais déterminez si une synchronisation de niveau supérieur est nécessaire, par exemple. peut-être au lieu d'utiliser StringBuffer, devriez-vous synchroniser les méthodes qui utilisent StringBuilder.
Voyons d’abord les similarités: StringBuilder et StringBuffer sont mutables. Cela signifie que vous pouvez en modifier le contenu, au même endroit.
Différences: StringBuffer est modifiable et synchronisé. StringBuilder est mutable, mais pas synchronisé par défaut.
Signification de synchronized (synchronisation): Quand quelque chose est synchronisé, plusieurs threads peuvent y accéder et le modifier sans aucun problème ni effet secondaire. StringBuffer est synchronisé, vous pouvez donc l'utiliser avec plusieurs threads sans aucun problème.
Lequel utiliser quand? StringBuilder: Lorsque vous avez besoin d'une chaîne pouvant être modifiable, et qu'un seul thread y accède et la modifie. StringBuffer: Lorsque vous avez besoin d'une chaîne, pouvant être modifiable, et que plusieurs threads y accèdent et la modifient.
Note: N'utilisez pas StringBuffer inutilement, c'est-à-dire, ne l'utilisez pas si un seul thread le modifie et y accède car il contient beaucoup de code de verrouillage et de déverrouillage pour la synchronisation, ce qui prendra inutilement du temps CPU . N'utilisez pas de cadenas sauf si cela est requis.
Dans les threads simples, StringBuffer n'est pas significativement plus lent que StringBuilder, grâce aux optimisations JVM. Et en multithreading, vous ne pouvez pas utiliser en toute sécurité un StringBuilder.
Voici mon test (pas un benchmark, juste un test):
public static void main(String[] args) {
String withString ="";
long t0 = System.currentTimeMillis();
for (int i = 0 ; i < 100000; i++){
withString+="some string";
}
System.out.println("strings:" + (System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuffer buf = new StringBuffer();
for (int i = 0 ; i < 100000; i++){
buf.append("some string");
}
System.out.println("Buffers : "+(System.currentTimeMillis() - t0));
t0 = System.currentTimeMillis();
StringBuilder building = new StringBuilder();
for (int i = 0 ; i < 100000; i++){
building.append("some string");
}
System.out.println("Builder : "+(System.currentTimeMillis() - t0));
}
Résultats :
chaînes: 319740
Tampons: 2
Constructeur: 7!
Ainsi, les constructeurs sont plus rapides que les tampons et beaucoup plus rapidement que la concaténation de chaînes. Utilisons maintenant un Executor pour plusieurs threads:
public class StringsPerf {
public static void main(String[] args) {
ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
//With Buffer
StringBuffer buffer = new StringBuffer();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(buffer));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Buffer : "+ AppendableRunnable.time);
//With Builder
AppendableRunnable.time = 0;
executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
StringBuilder builder = new StringBuilder();
for (int i = 0 ; i < 10; i++){
executorService.execute(new AppendableRunnable(builder));
}
shutdownAndAwaitTermination(executorService);
System.out.println(" Thread Builder: "+ AppendableRunnable.time);
}
static void shutdownAndAwaitTermination(ExecutorService pool) {
pool.shutdown(); // code reduced from Official Javadoc for Executors
try {
if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
pool.shutdownNow();
if (!pool.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("Pool did not terminate");
}
} catch (Exception e) {}
}
}
class AppendableRunnable<T extends Appendable> implements Runnable {
static long time = 0;
T appendable;
public AppendableRunnable(T appendable){
this.appendable = appendable;
}
@Override
public void run(){
long t0 = System.currentTimeMillis();
for (int j = 0 ; j < 10000 ; j++){
try {
appendable.append("some string");
} catch (IOException e) {}
}
time+=(System.currentTimeMillis() - t0);
}
}
Maintenant, StringBuffers prend 157 ms pour 100 000 ajouts. Ce n'est pas le même test, mais comparé aux 37 ms précédents, vous pouvez sans risque supposer que les ajouts de StringBuffers sont plus lents avec l'utilisation de la lecture multiple. La raison en est que le JIT/hotspot/compiler/quelque chose fait des optimisations quand il détecte qu'il n'y a pas besoin de vérifier les verrous.
Mais avec StringBuilder, vous avez Java.lang.ArrayIndexOutOfBoundsException, car un thread concurrent tente d'ajouter quelque chose là où il ne devrait pas.
La conclusion est que vous ne devez pas chasser StringBuffers. Et là où vous avez des discussions, réfléchissez à ce qu’elles font, avant d’essayer de gagner quelques nanosecondes.
StringBuilder a été introduit dans Java 1.5. Il ne fonctionnera donc pas avec les machines virtuelles antérieures.
Depuis le Javadocs :
La classe StringBuilder fournit une API compatible avec StringBuffer, mais sans garantie de synchronisation. Cette classe est conçue pour être utilisée comme remplacement immédiat de StringBuffer dans les endroits où le tampon de chaîne était utilisé par un seul thread (comme c'est généralement le cas). Dans la mesure du possible, il est recommandé d'utiliser cette classe plutôt que StringBuffer, car elle sera plus rapide dans la plupart des mises en œuvre.
Très bonne question
Voici les différences, j'ai remarqué:
StringBuffer: -
StringBuffer is synchronized
StringBuffer is thread-safe
StringBuffer is slow (try to write a sample program and execute it, it will take more time than StringBuilder)
StringBuilder: -
StringBuilder is not synchronized
StringBuilder is not thread-safe
StringBuilder performance is better than StringBuffer.
Chose banale :-
Les deux ont les mêmes méthodes avec les mêmes signatures. Les deux sont mutables.
StringBuffer
StringBuilder
StringBuffer
sans autre changementStringBuilder
et StringBuffer
sont presque identiques. La différence est que StringBuffer
est synchronisé et que StringBuilder
ne l’est pas. Bien que StringBuilder
soit plus rapide que StringBuffer
, la différence de performances est très faible. StringBuilder
remplace Sun par StringBuffer
. Cela évite simplement la synchronisation de toutes les méthodes publiques. Plutôt que cela, leur fonctionnalité est la même.
Exemple de bon usage:
Si votre texte va changer et est utilisé par plusieurs threads, il est préférable d'utiliser StringBuffer
. Si votre texte va changer mais est utilisé par un seul fil, utilisez StringBuilder
.
StringBuffer
StringBuffer est modifiable signifie que l'on peut changer la valeur de l'objet. L'objet créé via StringBuffer est stocké dans le tas. StringBuffer a les mêmes méthodes que StringBuilder, mais chaque méthode de StringBuffer est synchronisée, c'est-à-dire que StringBuffer est thread-safe.
pour cette raison, il ne permet pas à deux threads d'accéder simultanément à la même méthode. Chaque méthode est accessible par un thread à la fois.
Mais être thread-safe a aussi des inconvénients car les performances du StringBuffer sont atteintes en raison de la propriété thread-safe. Ainsi, StringBuilder est plus rapide que StringBuffer lorsqu'il appelle les mêmes méthodes de chaque classe.
La valeur de StringBuffer peut être changée, cela signifie qu’elle peut être assignée à la nouvelle valeur. De nos jours, c’est la question d’entrevue la plus courante, les différences entre les classes ci-dessus. Le tampon de chaîne peut être converti en chaîne à l'aide de la méthode toString ().
StringBuffer demo1 = new StringBuffer(“Hello”) ;
// The above object stored in heap and its value can be changed .
demo1=new StringBuffer(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuffer
StringBuilder
StringBuilder est identique au StringBuffer, c'est-à-dire qu'il stocke l'objet dans le tas et qu'il peut également être modifié. La principale différence entre StringBuffer et StringBuilder est que StringBuilder n'est également pas thread-safe. StringBuilder est rapide car il n'est pas thread-safe.
StringBuilder demo2= new StringBuilder(“Hello”);
// The above object too is stored in the heap and its value can be modified
demo2=new StringBuilder(“Bye”);
// Above statement is right as it modifies the value which is allowed in the StringBuilder
Ressource: String Vs StringBuffer Vs StringBuilder
String
est un immuable.
StringBuffer
est un mutable et synchronisé.
StringBuilder
est également modifiable mais n'est pas synchronisé.
Le javadoc explique la différence:
Cette classe fournit une API compatible avec StringBuffer, mais sans garantie de synchronisation. Cette classe est conçue pour être utilisée comme remplacement immédiat de StringBuffer dans les endroits où le tampon de chaîne était utilisé par un seul thread (comme c'est généralement le cas). Dans la mesure du possible, il est recommandé d'utiliser cette classe plutôt que StringBuffer, car elle sera plus rapide dans la plupart des mises en œuvre.
StringBuilder
(introduit dans Java 5) est identique à StringBuffer
, sauf que ses méthodes ne sont pas synchronisées. Cela signifie que ses performances sont meilleures que celles-ci, mais l’inconvénient est qu’il n’est pas thread-safe.
Lire tutoriel pour plus de détails.
Un programme simple illustrant la différence entre StringBuffer et StringBuilder:
/**
* Run this program a couple of times. We see that the StringBuilder does not
* give us reliable results because its methods are not thread-safe as compared
* to StringBuffer.
*
* For example, the single append in StringBuffer is thread-safe, i.e.
* only one thread can call append() at any time and would finish writing
* back to memory one at a time. In contrast, the append() in the StringBuilder
* class can be called concurrently by many threads, so the final size of the
* StringBuilder is sometimes less than expected.
*
*/
public class StringBufferVSStringBuilder {
public static void main(String[] args) throws InterruptedException {
int n = 10;
//*************************String Builder Test*******************************//
StringBuilder sb = new StringBuilder();
StringBuilderTest[] builderThreads = new StringBuilderTest[n];
for (int i = 0; i < n; i++) {
builderThreads[i] = new StringBuilderTest(sb);
}
for (int i = 0; i < n; i++) {
builderThreads[i].start();
}
for (int i = 0; i < n; i++) {
builderThreads[i].join();
}
System.out.println("StringBuilderTest: Expected result is 1000; got " + sb.length());
//*************************String Buffer Test*******************************//
StringBuffer sb2 = new StringBuffer();
StringBufferTest[] bufferThreads = new StringBufferTest[n];
for (int i = 0; i < n; i++) {
bufferThreads[i] = new StringBufferTest(sb2);
}
for (int i = 0; i < n; i++) {
bufferThreads[i].start();
}
for (int i = 0; i < n; i++) {
bufferThreads[i].join();
}
System.out.println("StringBufferTest: Expected result is 1000; got " + sb2.length());
}
}
// Every run would attempt to append 100 "A"s to the StringBuilder.
class StringBuilderTest extends Thread {
StringBuilder sb;
public StringBuilderTest (StringBuilder sb) {
this.sb = sb;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb.append("A");
}
}
}
//Every run would attempt to append 100 "A"s to the StringBuffer.
class StringBufferTest extends Thread {
StringBuffer sb2;
public StringBufferTest (StringBuffer sb2) {
this.sb2 = sb2;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
sb2.append("A");
}
}
}
StringBuffer:
StringBuilder
Générateur de cordes:
int one = 1;
String color = "red";
StringBuilder sb = new StringBuilder();
sb.append("One=").append(one).append(", Color=").append(color).append('\n');
System.out.print(sb);
// Prints "One=1, Colour=red" followed by an ASCII newline.
String-Buffer
StringBuffer sBuffer = new StringBuffer("test");
sBuffer.append(" String Buffer");
System.out.println(sBuffer);
Il est recommandé d'utiliser StringBuilder autant que possible car il est plus rapide que StringBuffer. Cependant, si la sécurité du thread est nécessaire, la meilleure option est d'utiliser les objets StringBuffer.
Mieux vaut utiliser StringBuilder car il n’est pas synchronisé et donc de meilleures performances. StringBuilder est un remplacement immédiat de l'ancien StringBuffer.
StringBuffer est modifiable. Cela peut changer en termes de longueur et de contenu. StringBuffers sont thread-safe, ce qui signifie qu'ils disposent de méthodes synchronisées pour contrôler l'accès, de sorte qu'un seul thread puisse accéder au code synchronisé d'un objet StringBuffer à la fois. Ainsi, les objets StringBuffer peuvent généralement être utilisés en toute sécurité dans un environnement multi-thread où plusieurs threads peuvent essayer d'accéder au même objet StringBuffer en même temps.
StringBuilder La classe StringBuilder est très similaire à StringBuffer, à la différence que son accès n'est pas synchronisé, de sorte qu'il n'est pas thread-safe. En l'absence de synchronisation, les performances de StringBuilder peuvent être meilleures que celles de StringBuffer. Ainsi, si vous travaillez dans un environnement à un seul thread, utiliser StringBuilder au lieu de StringBuffer peut entraîner une augmentation des performances. Ceci est également vrai pour d'autres situations telles qu'une variable locale StringBuilder (c'est-à-dire une variable dans une méthode) dans laquelle un seul thread accédera à un objet StringBuilder.
StringBuffer
est synchronisé, mais StringBuilder
ne l’est pas. En conséquence, StringBuilder
est plus rapide que StringBuffer
.
Puisque StringBuffer
est synchronisé, il nécessite un effort supplémentaire, donc basé sur les performances, il est un peu plus lent que StringBuilder
.
Il n'y a pas de différences fondamentales entre StringBuilder et StringBuffer, seules quelques différences existent entre eux. Dans StringBuffer, les méthodes sont synchronisées. Cela signifie qu’à la fois, un seul thread peut les exploiter. S'il y a plus d'un thread, le second devra attendre que le premier soit terminé et le troisième devra attendre que les premier et deuxième finissent, etc. Cela ralentit considérablement le processus et par conséquent, les performances dans le cas de StringBuffer sont faibles.
D'autre part, StringBuilder n'est pas synchronisé. Cela signifie qu’à la fois, plusieurs threads peuvent fonctionner simultanément sur le même objet StrinBuilder. Cela rend le processus très rapide et par conséquent, les performances de StringBuilder sont élevées.
StringBuffer est utilisé pour stocker des chaînes de caractères qui seront modifiées (les objets String ne peuvent pas être modifiés). Il se développe automatiquement selon les besoins. Classes connexes: String, CharSequence.
StringBuilder a été ajouté dans Java 5. Il est identique à tous égards à StringBuffer, à la différence qu'il n'est pas synchronisé, ce qui signifie que des problèmes peuvent survenir si plusieurs threads y accèdent en même temps. Pour les programmes à un seul thread, le cas le plus courant consiste à éviter très rapidement la synchronisation, ce qui rend le StringBuilder très légèrement plus rapide.
La principale différence est que StringBuffer
est synchronisé mais StringBuilder
ne l'est pas.Si vous devez utiliser plus d'un thread, StringBuffer est recommandé.Mais, selon la vitesse d'exécution StringBuilder
est plus rapide que StringBuffer
, car ce n'est pas synchronisé.
String est un objet immuable, ce qui signifie que la valeur ne peut pas être modifiée car StringBuffer est mutable.
StringBuffer est synchronisé, donc thread-safe, où StringBuilder ne l'est pas et ne convient que pour les instances à un seul thread.
Vérifiez les éléments internes de la méthode d’ajout synchronisé de StringBuffer
et de la méthode d’ajout non synchronisé de StringBuilder
.
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public synchronized StringBuffer append(Object obj) {
super.append(String.valueOf(obj));
return this;
}
public synchronized StringBuffer append(String str) {
super.append(str);
return this;
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
public StringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
public StringBuilder append(String str) {
super.append(str);
return this;
}
Puisque append est synchronized
, StringBuffer
a un surcoût de performance par rapport à StrinbBuilder
dans un scénario multitâche. Tant que vous ne partagez pas le tampon entre plusieurs threads, utilisez StringBuilder
, ce qui est rapide en raison de l'absence de synchronized
dans les méthodes d'ajout.
Voici le résultat des tests de performance pour String vs StringBuffer vs StringBuilder . Enfin, StringBuilder a remporté le test. Voir ci-dessous pour le code de test et le résultat.
Code :
private static void performanceTestStringVsStringbuffereVsStringBuilder() {
// String vs StringBiffer vs StringBuilder performance Test
int loop = 100000;
long start = 0;
// String
String str = null;
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
str += i + "test";
}
System.out.println("String - " + (System.currentTimeMillis() - start) + " ms");
// String buffer
StringBuffer sbuffer = new StringBuffer();
start = System.currentTimeMillis();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Buffer - " + (System.currentTimeMillis() - start) + " ms");
// String builder
start = System.currentTimeMillis();
StringBuilder sbuilder = new StringBuilder();
for (int i = 1; i <= loop; i++) {
sbuffer.append(i).append("test");
}
System.out.println("String Builder - " + (System.currentTimeMillis() - start) + " ms");
}
Résultat :
100 000 itérations pour l'ajout d'un seul texte
String - 37489 ms
String Buffer - 5 ms
String Builder - 4 ms
10000 itérations pour l'ajout d'un seul texte
String - 389 ms
String Buffer - 1 ms
String Builder - 1 ms
StringBuffer est synchronisé et thread-safe, StringBuilder n'est ni synchronisé ni plus rapide.
Chaque méthode présente dans StringBuffer est synchronisée. Par conséquent, à la fois, un seul thread est autorisé à utiliser l'objet StringBuffer. Il augmente le temps d'attente d'un thread et crée des problèmes de performances pour résoudre ce problème. Sun People a introduit StringBuilder dans la version 1.5.