ArrayList 소스 코드 와 다 중 스 레 드 보안 문제 분석
ArrayList 스 레 드 안전 문 제 를 분석 하기 전에 우 리 는 이러한 소스 코드 를 분석 하여 스 레 드 안전 문제 가 발생 할 수 있 는 곳 을 찾 은 다음 에 코드 를 검증 하고 분석 합 니 다.
1.1 데이터 구조
ArrayList 내 부 는 배열 로 요 소 를 저장 합 니 다.데이터 정 의 는 다음 과 같 습 니 다.
transient Object[] elementData; // non-private to simplify nested class access
Array List 에서 이 배열 은 자원 을 공유 하 는 것 입 니 다.다 중 스 레 드 가 이 데 이 터 를 조작 할 때 동기 화 통 제 를 하지 않 으 면 스 레 드 안전 문제 가 발생 할 수 있 습 니 다.1.2 add 방법 에 나타 날 수 있 는 문제점 분석
우선 add 의 소스 코드 를 살 펴 보 겠 습 니 다.다음 과 같 습 니 다.
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
이 방법 에는 두 가지 조작 이 있 는데 하 나 는 배열 용량 검사 이 고 다른 하 나 는 요 소 를 데이터 에 넣 는 것 이다.우 리 는 먼저 두 번 째 간단 한 분석 을 시작 합 니 다.여러 스 레 드 의 실행 순서 가 다음 과 같 을 때 최종 데이터 요소 의 개 수 는 기대 치보다 작 습 니 다.이 순서대로 실 행 된 후에 우 리 는 element Data[n]의 값 이 두 번 만 설정 되 었 고 두 번 째 스 레 드 설정 의 값 은 이전 것 을 덮어 쓰 고 마지막 size=n+1 을 볼 수 있 습 니 다.다음은 코드 를 사용 하여 이 문 제 를 검증 합 니 다.
1.3 코드 검증
먼저 다음 코드 를 보고 1000 개의 스 레 드 를 열 고 ArrayList 의 add 방법 을 호출 합 니 다.각 스 레 드 는 ArrayList 에 100 개의 숫자 를 추가 합 니 다.프로그램 이 정상적으로 실 행 될 경우 출력 해 야 합 니 다.
list size is :10000
코드 는 다음 과 같 습 니 다:
private static List<Integer> list = new ArrayList<Integer>();
private static ExecutorService executorService = Executors.newFixedThreadPool(1000);
private static class IncreaseTask extends Thread{
@Override
public void run() {
System.out.println("ThreadId:" + Thread.currentThread().getId() + " start!");
for(int i =0; i < 100; i++){
list.add(i);
}
System.out.println("ThreadId:" + Thread.currentThread().getId() + " finished!");
}
}
public static void main(String[] args){
for(int i=0; i < 1000; i++){
executorService.submit(new IncreaseTask());
}
executorService.shutdown();
while (!executorService.isTerminated()){
try {
Thread.sleep(1000*10);
}catch (InterruptedException e){
e.printStackTrace();
}
}
System.out.println("All task finished!");
System.out.println("list size is :" + list.size());
}
이 main 방법 을 실행 하면 다음 과 같이 출력 합 니 다.이상 의 실행 결 과 를 보면 마지막 출력 결 과 는 우리 의 기대 치보다 작 을 것 이다.즉,다 중 스 레 드 가 add 방법 을 호출 할 때 요소 가 덮어 쓰 는 문제 가 발생 합 니 다.
1.4 배열 용량 검사 의 병발 문제
add 방법 소스 코드 에서 우 리 는 요 소 를 추가 할 때마다 배열 용량 의 검 측 이 있 는 것 을 보 았 습 니 다.add 에서 이 방법 을 호출 하 는 소스 코드 는 다음 과 같 습 니 다.
ensureCapacityInternal(size + 1);
용량 검사 와 관련 된 소스 코드 는 다음 과 같 습 니 다.
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
용량 검사 의 흐름 도 는 다음 과 같다.우 리 는 두 개의 스 레 드 로 add 작업 을 수행 하여 확장 용량 에 발생 할 수 있 는 병발 문 제 를 분석 합 니 다.
Array List 를 새로 만 들 때 내부 배열 용기 의 용량 은 기본 용량 10 입 니 다.두 스 레 드 로 10 번 째 요 소 를 동시에 추가 할 때 다음 과 같은 실행 순서 가 나타 나 면 자바.lang.Array Index OutOf Bounds Exception 이상 을 던 질 수 있 습 니 다.
두 번 째 스 레 드 가 배열 에 데 이 터 를 추가 할 때 배열 의 용량 이 10 이기 때문에 이 작업 은 index 가 10 인 위치 에 요소 값 을 설정 하기 때문에 배열 의 경계 이상 을 던 집 니 다.
1.5 코드 검증 배열 용량 검사 의 병행 문제
다음 코드 사용:
private static List<Integer> list = new ArrayList<Integer>(3);
private static ExecutorService executorService = Executors.newFixedThreadPool(10000);
private static class IncreaseTask extends Thread{
@Override
public void run() {
System.out.println("ThreadId:" + Thread.currentThread().getId() + " start!");
for(int i =0; i < 1000000; i++){
list.add(i);
}
System.out.println("ThreadId:" + Thread.currentThread().getId() + " finished!");
}
}
public static void main(String[] args){
new IncreaseTask().start();
new IncreaseTask().start();
}
main 방법 을 실행 하면 콘 솔 출력 을 다음 과 같이 볼 수 있 습 니 다.1.6 Array List 의 다른 방법 설명
Array List 에 공 유 된 변 수 를 조작 하 는 다른 방법 도 병행 안전 문제 가 있 을 수 있 으 므 로 상기 분석 방법 에 따라 분석 하면 된다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Java의 ArrayList 작동 원리 상세 정보수조로 실현하다.공간을 절약하지만 수조는 용량 제한이 있다.제한을 초과하면 50% 용량이 증가하며 System을 사용합니다.arraycopy () 를 새 그룹으로 복사합니다.따라서 수조 크기의 예비 평가를 하는 것이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.