Comparing the Connection Efficiency of String, String Builder Strings and Thread Safety of String Builder and String Buffer Strings

I. The Efficiency of String Connection

Why is it slow to connect strings with String?

Small Knowledge Points

After initializing the array in java, the memory space and the length of the array are immutable.

Creating a string to allocate memory space for string objects will consume a certain amount of time (CPU) and space (memory) costs. As the most basic data type, a large number of frequent string creation will greatly affect the performance of the program.

Too many useless intermediaries

Each time a string is connected, a new String object is created, and as the number of splices increases, the object becomes larger and larger.
For example, 100 String objects need to be created for 100 stitches to achieve the goal.

Why is StringBuilder more efficient when connecting?

Character array expansion mechanism:

private void ensureCapacityInternal(int minimumCapacity) {
         // Is the minimum required capacity minimum Capacity longer than the original array length
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }
    
private int newCapacity(int minCapacity) {
         // Calculate the capacity of new capacity after expansion
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        // After expansion, the capacity is still less than the minimum required capacity.
        if (newCapacity - minCapacity < 0) {
            // Set the new capacity to the minimum required capacity minimum Capacity
            newCapacity = minCapacity;
        }
        // Whether or not new Capacity overflows and whether new Capacity is larger than the maximum capacity MAX_ARRAY_SIZE that an array can allocate.
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

    private int hugeCapacity(int minCapacity) {
        // A memory overflow exception is thrown when the minimum required capacity minCapacity is greater than Integer.MAX_VALUE
        if (Integer.MAX_VALUE - minCapacity < 0) { // overflow
            throw new OutOfMemoryError();
        }
        // If minCapacity is between MAX_ARRAY_SIZE and Integer.MAX_VALUE, the new capacity is minCapacity, otherwise MAX_ARRAY_SIZE is directly used as the new capacity.
        return (minCapacity > MAX_ARRAY_SIZE)
            ? minCapacity : MAX_ARRAY_SIZE;
    }

When a string is appended to the original StringBuilder object:

1. Append'null'character when str is null

2. Confirm whether expansion operations are needed

2.1 Whether the minimum required capacity minimum Capacity is longer than the original array length, that is, when the original array length can not meet the minimum required capacity, the expansion operation is carried out.  
2.2 Calculate the capacity after expansion, newCapacity = value. length * 2 + 2.  
2.3 Whether the new capacity is less than the minimum required capacity after expansion, and if it is less than the minimum required capacity, the new capacity is directly set to the minimum required capacity.  
2.4 Whether or not new Capacity overflows and whether new Capacity is larger than the maximum capacity MAX_ARRAY_SIZE that an array can allocate. If so, it can be judged that a memory overflow exception is thrown when the minimum required capacity minCapacity is greater than Integer.MAX_VALUE. If minCapacity is between MAX_ARRAY_SIZE and Integer.MAX_VALUE, the new capacity is minCapacity, otherwise MAX_ARRAY_SIZE is used directly as the new capacity.  

3.str.getChars() appends STR to the end of value

Reasons for high efficiency

  1. The expansion mechanism guarantees that only when minimum capacity - value. length > 0 meets the expansion condition, new arrays will be generated. So most of the cases are to operate on the original arrays, which avoids generating too many useless char [] objects and saves the overhead of system resources.

Code

/**
 * Compare string connection speed
 *
 * @Author: lingyejun
 * @Date: 2019/8/17
 * @Describe:
 * @Modified By:
 */
public class LinkCompare {

    /**
     * Primitive string concatenation
     *
     * @param times
     */
    public static void linkByString(int times) {

        Long startTime = System.currentTimeMillis();

        String initStr = "";
        for (int i = 0; i < times; i++) {
            initStr = initStr + i;
        }

        Long endTime = System.currentTimeMillis();

        System.out.println("String Connect " + times + " Secondary consumption:" + (endTime - startTime) + "ms");
    }

    /**
     * Connecting strings using StringBuilder
     *
     * @param times
     */
    public static void linkByStringBuilder(int times) {

        Long startTime = System.currentTimeMillis();

        StringBuilder initStr = new StringBuilder();
        for (int i = 0; i < times; i++) {
            initStr.append(i);
        }

        Long endTime = System.currentTimeMillis();

        System.out.println("StringBuilder Connect " + times + " Secondary consumption:" + (endTime - startTime) + "ms");
    }


    /**
     * Connecting strings using StringBuffer
     *
     * @param times
     */
    public static void linkByStringBuffer(int times) {

        Long startTime = System.currentTimeMillis();

        StringBuffer initStr = new StringBuffer();
        for (int i = 0; i < times; i++) {
            initStr.append(i);
        }

        Long endTime = System.currentTimeMillis();

        System.out.println("StringBuffer Connect " + times + " Secondary consumption:" + (endTime - startTime) + "ms");
    }


    public static void main(String[] args) {

        // 100000000
        linkByStringBuilder(40000);
        //-XX:+PrintGCDetails
        //linkByString(40000);

    }
}

2. Thread security comparison between String Builder and String Buffer

Verify thread security of StringBuffer

Reasons for thread insecurity

public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
    
public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }

Test code

import java.util.ArrayList;
import java.util.List;

/**
 * StringBuilder Concurrent Test with StringBuffer
 *
 * @Author: lingyejun
 * @Date: 2019/8/17
 * @Describe:
 * @Modified By:
 */
public class SecurityCompare {

    public void stringBuilderTest() {

        // Initialize StringBuilder
        StringBuilder stringBuilder = new StringBuilder();

        // joinList
        List<StringBuilderThread> joinList = new ArrayList<>();

        // Simulate concurrent scenarios
        for (int i = 0; i < 1000; i++) {
            StringBuilderThread sbt = new StringBuilderThread(stringBuilder);
            sbt.start();
            joinList.add(sbt);
        }

        // Wait for the append thread to finish executing before executing the main thread
        for (StringBuilderThread thread : joinList) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // Print the final result
        System.out.println("StringBuilder Concurrent append Results: " + stringBuilder.length());
    }

    public void stringBufferTest() {

        // Initialize StringBuffer
        StringBuffer stringBuffer = new StringBuffer();

        // joinList
        List<StringBufferThread> joinList = new ArrayList<>();

        // Simulate concurrent scenarios
        for (int i = 0; i < 1000; i++) {
            StringBufferThread sbf = new StringBufferThread(stringBuffer);
            sbf.start();
            joinList.add(sbf);
        }

        // Wait for the append thread to finish executing before executing the main thread
        for (StringBufferThread thread : joinList) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        // Print the final result
        System.out.println("StringBuffer Concurrent append Results: " + stringBuffer.length());
    }


    public static void main(String[] args) {

        SecurityCompare securityCompare = new SecurityCompare();

        securityCompare.stringBuilderTest();
        securityCompare.stringBufferTest();

    }

    public static class StringBuilderThread extends Thread {

        private StringBuilder stringBuilder;

        public StringBuilderThread(StringBuilder stringBuilder) {
            this.stringBuilder = stringBuilder;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stringBuilder.append("a");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    private static class StringBufferThread extends Thread {

        private StringBuffer stringBuffer;

        public StringBufferThread(StringBuffer stringBuffer) {
            this.stringBuffer = stringBuffer;
        }

        @Override
        public void run() {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stringBuffer.append("a");
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}

III. CONCLUSION

String is a fixed length string, StringBuilder and StringBuffer are variable length strings.
2.StringBuffer is thread-safe and StringBuilder is non-thread-safe.
3. The default initial capacity of StringBuilder and StringBuffer is 16, which can predict the length of the string in advance and further reduce the additional cost of expansion.

Tags: Java less

Posted on Sat, 24 Aug 2019 23:26:17 -0700 by devarticles