StringBuilder 스레드가 안전하지 않은 이유, StringBuffer 스레드가 안전한 이유

2981 단어 JDK 소스
StringBuilder와StringBuffer의 내부 구현은String클래스와 마찬가지로 하나의char수조를 통해 문자열을 저장한다. 다른 것은String클래스 안의char수조는final로 수식되어 있어 변할 수 없는 것이고StringBuilder와StringBuffer의char수조는 변할 수 있는 것이다.
라인 안전 문제에 관해서는 그들의 jdk 원본을 보아야 한다.
1. StringBuilder
  • 우리 직통 append() 방법
  • public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
  • StringBuilder가AbstractStringBuilder를 계승했기 때문에 부류의 append() 방법을 찾아라
  • 변수 설명:
    //        
    char[] value;
    //            
    int count;
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        //        
        ensureCapacityInternal(count + len);
        // str  value  
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

    우리는count+=len이 원자 조작이 아니라 여러 개의 라인을 조작할 때 기대치와 어긋나는 상황이 발생하여 전체count가 기대보다 작다는 것을 알 수 있다.
    두 번째 문제는 Array Index Out Of Bounds Exception 이상을 던질 수 있다는 것이다. 예를 들어 두 개의 라인이 append 조작을 하고 라인 1이 ensure Capacity Internal 확장을 한 후에 타임 필름이 다 떨어졌다. 이때 라인 2가 append를 실행하고 용량을 마침 다 썼다. 라인 1이 실행된str.get Chars를 기다리면 Array Index Out Of Bounds Exception 이상을 던진다.
  • 보충:
  • 용량이 부족할 때, 확장은 원래의 2배 길이이고, 만약 충분하지 않으면 미니멀 캐피티를 가져와, 마지막에 새 그룹을 만들어서 값을 복사합니다
    /**
         * This method has the same contract as ensureCapacity, but is
         * never synchronized.
         */
        private void ensureCapacityInternal(int minimumCapacity) {
            // overflow-conscious code
            if (minimumCapacity - value.length > 0)
                expandCapacity(minimumCapacity);
        }
    
    /**
         * This implements the expansion semantics of ensureCapacity with no
         * size check or synchronization.
         */
        void expandCapacity(int minimumCapacity) {
            //     2    2
            int newCapacity = value.length * 2 + 2;
            //    str.length()+value.length   
            if (newCapacity - minimumCapacity < 0)
                newCapacity = minimumCapacity;
            if (newCapacity < 0) {
                if (minimumCapacity < 0) // overflow
                    throw new OutOfMemoryError();
                newCapacity = Integer.MAX_VALUE;
            }
            //        ,      
            value = Arrays.copyOf(value, newCapacity);
        }
    
    public static char[] copyOf(char[] original, int newLength) {
            char[] copy = new char[newLength];
            System.arraycopy(original, 0, copy, 0,
                             Math.min(original.length, newLength));
            return copy;
        }

    2. StringBuffer
    StringBuilder와 마찬가지로 StringBuffer도 AbstractStringBuilder의 하위 클래스입니다.다른 것은 StringBuffer가 append와 delete 작업을 할 때 동기화 자물쇠를 넣었다는 것이다.
    public synchronized StringBuffer append(String str) {
            toStringCache = null;
            super.append(str);
            return this;
        }
    
    public synchronized StringBuffer delete(int start, int end) {
            toStringCache = null;
            super.delete(start, end);
            return this;
        }

    참조:

    좋은 웹페이지 즐겨찾기