What does “ StringBuilders are not thread-safe” mean?

前端 未结 5 1753
攒了一身酷
攒了一身酷 2020-12-31 12:51

I have read some articles about the pros and cons of String and StringBuilder in the Java Programming language. In one of the articles, the author

5条回答
  •  说谎
    说谎 (楼主)
    2020-12-31 13:27

    The thread-safety issue with StringBuilder is that method calls on a StringBuilder do not synchronize.

    Consider the implementation of the StringBuilder.append(char) method:

    public StringBuilder append(boolean b) {
        super.append(b);
        return this;
    }
    
    // from the superclass
    public AbstractStringBuilder append(char c) {
         int newCount = count + 1;
         if (newCount > value.length)
             expandCapacity(newCount);
         value[count++] = c;
         return this;
     }
    

    Now suppose that you have two thread that are sharing a StringBuilder instance, and both attempt to append a character at the same time. Suppose that they both get to the value[count++] = c; statement at the same time, and that count is 1. Each one will write its character into the buffer at value[1], and then update count. Obviously only one character can be stored there ... so the other one will be lost. In addition, one of the increments to count will probably be lost.

    Worse than that, the value[count++] = c; statement can fail even if the two threads don't arrive there at the same time. The reason is that the Java memory model says that unless there is proper synchronization (a "happens before" relationship), it is not guaranteed that the second thread will see the memory updates made by the first thread. What actually happens depends on whether and when the first thread's updates are written through to main memory.


    Now lets look at StringBuffer.append(char):

    public synchronized StringBuffer append(char c) {
        super.append(c);  // calls the "AbstractStringBuilder.append" method above.
        return this;
    }
    

    Here we see that the append method is synchronized. This means two things:

    • Two threads cannot execute the superclass append method on the same StringBuffer object at the same time. Thus the first scenario cannot happen.

    • The synchronize means that there is a happens before between successive calls to StringBuffer.append made by different threads. That means that the later thread is guaranteed to see the updates made in the earlier one.


    The String case is different again. If we examine the code, we will see that there is no overt synchronization. But that's OK, because a String object is effectively immutable; i.e are no methods in the String API that will result in an externally observable change in the String object's state. In addition:

    • The special behaviour of final instance variables and constructors means that the all threads will see the correct initial state for any String.

    • In the one place where the String is mutable behind the scenes, the hashCode() method will work correctly whether or not a thread sees the most recent changes to the hash variable.


    References:

    • Source code for StringBuilder - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/lang/StringBuilder.java
    • Source code for StringBuffer - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/lang/StringBuffer.java
    • Source code for String - http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8-b132/java/lang/String.java

提交回复
热议问题