멀티 쓰레드 상황이 아닌데도 ConcurrentModificationException 을 마주하는 경우가 있습니다.
대부분의 경우 Iterator 를 사용하여 순회를 하는 도중에 변경을 시도했기 때문입니다.
- 컬렉션의
Iterator가생성된 이후 컬렉션의구조가 변경되면 Iterator 는ConcurrentModificationException를 발생시킵니다.
이를fail-fast메커니즘이라 합니다.- 컬렉션에서 직접 변경 메서드를 호출하는 것이 아닌,
Iterator가제공하는 변경 메서드(remove())를 사용하면 안전합니다.
List<String> list = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String item = iterator.next();
if (item.equals("banana")) {
iterator.remove(); // safe
}
}
System.out.println(list);
Collection에서 제공하는removeIf(),removeAll(),retainAll()도 대안이 될 수 있습니다.
Collections유틸리티 클래스에서 Collection 들을 위한decorate메서드들을 제공합니다.
synchronizedXXX()-멀티 스레드상황을 위한 decorate 메서드
- synchronizedCollection(Collection c), synchronizedList(List list), synchronizedSet(Set s), synchronizedMap(Map m)
unmodifiableXXX()-읽기 전용컬렉션을 만들기 위한 decorate 메서드
- unmodifiableCollection(Collection c), unmodifiableList(List list), unmodifiableSet(Set s), unmodifiableMap(Map m)
singletonXXX()-단 하나의 객체만을 저장하는 컬렉션을 만들기 위한 decorate 메서드
- singletonList(Object o), singleton(Object o), singletonMap(Object key, Object value)
상황에 맞는 인터페이스와 구현체를 사용합니다.
자료구조 인터페이스 싱글 스레드 환경에 적합한 구현체 및 간단한 설명 멀티 스레드 환경에 적합한 구현체 및 간단한 설명 List ArrayList: 배열 기반, 빠른 인덱스 접근.CopyOnWriteArrayList: 읽기 잦고 쓰기 적을 때 유용, 쓰기 시 복사.LinkedList: 빠른 중간 삽입/삭제.Collections.synchronizedList(new LinkedList<>()): 동기화 래퍼, 전체 락.Vector(Legacy): 동기화 지원 (성능 낮음).Set HashSet: 순서 없음, 빠른 검색.ConcurrentSkipListSet: 정렬된 Set, 락-프리, 높은 동시성.LinkedHashSet: 삽입 순서 유지.Collections.synchronizedSet(new LinkedHashSet<>()): 동기화 래퍼.TreeSet: 자동 정렬.Collections.synchronizedSortedSet(new TreeSet<>()): 동기화 래퍼.Queue LinkedList: FIFO.ConcurrentLinkedQueue: 락-프리 FIFO, 높은 동시성.PriorityQueue: 우선순위 기반.PriorityBlockingQueue: 우선순위 기반 블로킹 큐.ArrayDeque: 양방향 큐.LinkedBlockingQueue: 블로킹 FIFO, 용량 제한 가능.Deque LinkedList: 양방향 삽입/삭제.ConcurrentLinkedDeque: 락-프리 양방향 큐, 높은 동시성.ArrayDeque: 효율적인 양방향 삽입/삭제.LinkedBlockingDeque: 블로킹 양방향 큐, 용량 제한 가능.Map HashMap: 빠른 키 검색.ConcurrentHashMap: 높은 동시성, 빠른 읽기.LinkedHashMap: 삽입 순서 유지.Collections.synchronizedMap(new LinkedHashMap<>()): 동기화 래퍼.TreeMap: 키 기준 자동 정렬.ConcurrentSkipListMap: 정렬된 Map, 락-프리, 높은 동시성.Hashtable(Legacy): 동기화 지원 (성능 낮음), null 불가.
Java 의 소스코드에서 compareTo() 의 구현 방식들을 확인할 수 있습니다.
이러한 코드들에서 자바 코드를최적화하는 방법들을 배울 수 있습니다.// compareTo in Integer class public int compareTo(Integer anotherInteger) { return compare(this.value, anotherInteger.value); } public static int compare(int x, int y) { return (x < y) ? -1 : ((x == y) ? 0 : 1); }뺄셈이 아니라 삼항 연산자를 두번 사용함으로써 모든 자리수의 계산을 할 필요가 없어지고, 대소비교를 동등비교보다 먼저 함으로써 비교를 두번 해야하는 경우를 줄였습니다.
- Map 인터페이스의 구현체인 Hashtable 을 상속받은 Properties 는 key 와 value 모두 String 인 딕셔너리 구조입니다.
- 주로 애플리케이션의
환경설정과 관련된속성을 저장하는데 사용되며 데이터를파일로부터읽고쓰는편리한 기능들을 제공합니다.
메서드 짧은 설명 getProperty(String key)키로 값(String) 조회, 없으면 null.getProperty(String key, String defaultValue)키로 값(String) 조회, 없으면 defaultValue.setProperty(String key, String value)키-값(String) 설정. load(InputStream inStream)바이트 스트림에서 속성 로드. load(Reader reader)문자 스트림에서 속성 로드. store(OutputStream out, String comments)속성 저장 (바이트 스트림, 주석). store(Writer writer, String comments)속성 저장 (문자 스트림, 주석). stringPropertyNames()모든 키(String) Set 반환. propertyNames()모든 키(String) Enumeration 반환 (Legacy). list(PrintStream out)속성 목록 출력 (PrintStream). list(PrintWriter out)속성 목록 출력 (PrintWriter). defaults()기본 속성 객체 반환. getProperty(String key, Properties defaults)키로 속성 검색, 없으면 기본 속성에서 검색. save(OutputStream out, String comments)속성 저장 (Legacy, 예외 처리 다름).