Imagine a real parallel scenario in which a StringBuffer should be used than a StringBuilder?

I know the difference between StringBuffer and StringBuilder. read here !

And anyway, as javadoc says,

Whenever possible, it is recommended that this class be used in the StringBuffer preference, as it will be faster in most implementations.

But, the javadoc from StringBuilder also says:

StringBuilder instances StringBuilder unsafe for use by multiple threads. If such synchronization is required, it is recommended to use {@link java.lang.StringBuffer}

So, I am wondering, does a StringBuffer preference really exist? And since mutable string is used mainly in one thread, can anyone give me a parallel real script that is preferable to StringBuffer?

+6
source share
4 answers

The reason StringBuffer is thread safe is because at the time the first version of the java api was developed, people approached concurrency in a different way than these days. The prevailing view was that objects should be thread safe - since Java supports threads, and people can use any JDK class in multiple threads. Later, when Java started optimizing for runtime, the cost of those unnecessary synchronization blocks became a problem, so the new APIs were designed to not sync. Even later, the JVM began to optimize locks to such an extent that unprotected locks became almost free, which made the whole decision controversial.

StringBuffer is still thread safe because old code can rely on it being thread safe. This is far from typical use, but conceivable.

For example, suppose you are writing a journal application that forwards journal entries to a central server. Since we do not want to block the caller while waiting for network I / O, we do this in a dedicated stream. Other threads will accumulate log entries in StringBuffer:

 class RemoteLogger implements Runnable, Appender { final StringBuffer buffer = new StringBuffer(); void append(String s) { buffer.append(s); } public void run() { for (;;) { Thread.sleep(100); String message = buffer.toString(); sendToServer(message); buffer.delete(0, message.length()); } } } 
+5
source

The simple answer is NO. IMHO there is no normal situation when you would use StringBuffer instead of StringBuilder or other class. Creating thread safety StringBuffer may make your code less thread safe because people mistakenly assume that if you used StringBuffer your code is thread safe if it is not.

If you used StringBuffer, at some point you need to use synchronization, although for most developers this is not always clear, and I saw a lot of errors when this (even in mature libraries) was not executed or was not done correctly. Much better, you use StringBuilder and lock, sequentially, sequentially.

Why a synchronized StringBuffer has never been a good idea.

- this is the case when StringBuffer is preferred, really exists

There is one use case; you have a library that only accepts the StringBuffer API in the API. This is a poor design for the reason mentioned above, but not the library is perfect .;)

+4
source

In any case, when a text buffer may be available at the same time.

As an example, how about having multiple message flows that will output data over the network. In this case, perhaps they use a common text buffer and simply write to it, and when the buffer is full, it can be sent over the network.

+3
source

The following program sometimes throws exceptions when using StringBuilder, but will never throw an exception when using StringBuffer.

Program:

 public class StringBuilderConcurrent { static final StringBuilder sb = new StringBuilder(); // shared memory public static void main(String[] args) throws Exception { int NUM_WRITERS = 300; ArrayList<WriterThread> threads = new ArrayList<WriterThread>(NUM_WRITERS); for (int i = 0; i < NUM_WRITERS; i++) { WriterThread wt = new WriterThread("writerThread" + i); threads.add(wt); wt.start(); } for (int i = 0; i < threads.size(); i++) { threads.get(i).join(); } System.out.println(sb); } public static class WriterThread extends Thread { public WriterThread(String name) { super(name); } public void run() { String nameNl = this.getName() + "\n"; for (int i = 1; i < 20; i++) { sb.append(nameNl); } } }; } 

Since StringBuilder ( sb ) is not thread safe, having multiple streams to write data to sb can damage sb (for example, unexpected null characters, word letters interspersed with some other letters). It is also possible for the internal state of sb become inconsistent enough to throw an exception:

 Exception in thread "writerThread0" java.lang.ArrayIndexOutOfBoundsException at java.lang.System.arraycopy(Native Method) at java.lang.String.getChars(String.java:854) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:391) at java.lang.StringBuilder.append(StringBuilder.java:119) at test.StringBuilderConcurrent$WriterThread.run(StringBuilderConcurrent.java:35) 

The following program is identical to the first, except that it uses StringBuffer instead of StringBuilder. It will never encounter an ArrayIndexOutOfBoundsException error.

 public class StringBufferConcurrent { static final StringBuffer sb = new StringBuffer(); // shared memory public static void main(String[] args) throws Exception { int NUM_WRITERS = 300; ArrayList<WriterThread> threads = new ArrayList<WriterThread>(NUM_WRITERS); for (int i = 0; i < NUM_WRITERS; i++) { WriterThread wt = new WriterThread("writerThread" + i); threads.add(wt); wt.start(); } for (int i = 0; i < threads.size(); i++) { threads.get(i).join(); } System.out.println(sb); } public static class WriterThread extends Thread { public WriterThread(String name) { super(name); } public void run() { String nameNl = this.getName() + "\n"; for (int i = 1; i < 20; i++) { sb.append(nameNl); } } }; } 

Whether these programs are representative of the "real world" problem is a rather subjective question. I will leave this decision to the audience.

+2
source

Source: https://habr.com/ru/post/945435/


All Articles