Java 동시 프로그래밍: 동시 컨테이너 CopyOnWriteArrayList의 구현 원리
COW라고도 하는 Copy-On-Write는 프로그래밍에 사용되는 최적화 전략입니다. 기본 아이디어는 모든 사람이 처음부터 동일한 콘텐츠를 공유한다는 것입니다. 누군가가 콘텐츠를 수정하려고 하면 실제로 콘텐츠를 복사하여 새로운 콘텐츠를 만든 다음 이를 수정합니다. 이것은 일종의 지연된 게으름 전략입니다. JDK1.5부터 Java 동시성 패키지는 CopyOnWrite 메커니즘을 사용하여 구현된 두 개의 동시 컨테이너(CopyOnWriteArrayList 및 CopyOnWriteArraySet)를 제공합니다. CopyOnWrite 컨테이너는 매우 유용하며 여러 동시 시나리오에서 사용할 수 있습니다.
CopyOnWrite 컨테이너란 무엇인가요?
CopyOnWrite 컨테이너는 쓰기 시 복사되는 컨테이너입니다. 컨테이너에 요소를 추가할 때 현재 컨테이너에 직접 추가하는 것이 아니라 먼저 현재 컨테이너를 복사하여 새 컨테이너를 만든 다음 요소를 추가한 후 새 컨테이너에 요소를 추가한다는 것이 널리 이해되고 있습니다. 그런 다음 원래 컨테이너의 참조가 새 컨테이너를 가리키도록 합니다. 이것의 장점은 현재 컨테이너가 어떤 요소도 추가하지 않기 때문에 잠금 없이 CopyOnWrite 컨테이너에서 동시 읽기를 수행할 수 있다는 것입니다. 따라서 CopyOnWrite 컨테이너도 읽기와 쓰기를 분리한 아이디어이고, 읽기와 쓰기는 서로 다른 컨테이너입니다.
CopyOnWriteArrayList의 구현 원리
CopyOnWriteArrayList를 사용하기 전에 소스 코드를 읽고 어떻게 구현되는지 살펴보겠습니다. 다음 코드는 CopyOnWriteArrayList의 add 메소드 구현입니다(CopyOnWriteArrayList에 요소 추가). 추가할 때 잠궈야 한다는 것을 알 수 있습니다. 그렇지 않으면 여러 스레드로 쓸 때 N 개의 복사본이 복사됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
/**
|
读的时候不需要加锁,如果读的时候有多个线程正在向CopyOnWriteArrayList添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的CopyOnWriteArrayList。
1 2 3 |
* 지정된 요소를 이 목록의 끝에 추가합니다.
|
* @param 이 목록에 추가할 요소
#🎜🎜#
#🎜🎜#
* @return <tt>true</tt> ({@link Collection#add}로 지정됨)
#🎜🎜#
#🎜🎜#
*/
#🎜🎜#
#🎜🎜#
공개
부울
add(E e) {
#🎜🎜#
#🎜🎜#
final
ReentrantLock 잠금 =
this
.lock;
#🎜🎜 #
#🎜🎜#
lock.lock();
#🎜🎜#
#🎜🎜#
시도
{
#🎜🎜#
#🎜🎜#
Object[] 요소 = getArray();
#🎜🎜#
#🎜🎜#
int
len = elements.length;
#🎜🎜#
#🎜🎜#
Object[] newElements = Arrays.copyOf(elements, len +
1
);
#🎜 🎜#
#🎜🎜#
newElements[len] = e;
#🎜🎜#
#🎜🎜#
setArray(newElements);
#🎜🎜#
#🎜🎜#
return
true
;
#🎜🎜#
#🎜🎜#
}
드디어
{
#🎜🎜#
#🎜🎜#
lock.unlock();
#🎜🎜#
#🎜🎜# }#🎜🎜#
#🎜🎜# }#🎜🎜#
#🎜🎜#
#🎜🎜##🎜🎜##🎜🎜##🎜🎜# 읽을 때 여러 스레드가 CopyOnWriteArrayList에 데이터를 추가하는 경우 읽기에서는 여전히 이전 데이터를 읽습니다. 잠기지 않습니다. #🎜🎜##🎜🎜##🎜🎜##🎜🎜##🎜🎜#
#🎜🎜#1#🎜🎜#
#🎜🎜#2#🎜🎜#
#🎜🎜#3#🎜🎜#
#🎜🎜#
#🎜🎜#
#🎜🎜#공개
E get(
int
index) {
#🎜🎜#
#🎜🎜#
return
get(getArray(), index);
#🎜🎜#
#🎜🎜#}#🎜🎜#
#🎜🎜#
#🎜🎜##🎜🎜##🎜🎜#CopyOnWriteMap은 JDK에서 제공되지 않습니다. CopyOnWriteArrayList를 참조하여 구현할 수 있습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
가져오기 java.util.Map;
|
공개
클래스
CopyOnWriteMap<k v> </k>
구현
Map<k v> , 복제 가능 {</k>
#🎜🎜#
#🎜🎜#
비공개
휘발성
Map<K, V>
#🎜🎜#
#🎜🎜# #🎜🎜#
#🎜🎜#
공개
CopyOnWriteMap() {
#🎜🎜#
#🎜🎜#
internalMap =
new
HashMap<K, V>();
#🎜🎜#
#🎜🎜# }#🎜🎜#
#🎜🎜# #🎜🎜#
#🎜🎜#
public
V put(K 키, V 값) {
#🎜🎜#
#🎜🎜# #🎜🎜#
#🎜🎜#
동기화
(
이것
) {
#🎜🎜#
#🎜🎜#
Map<k v> newMap = </k>
new
HashMap<k v>(internalMap);</k>
#🎜🎜#
#🎜🎜#
V val = newMap.put(키, 값);
#🎜🎜#
#🎜🎜#
internalMap = newMap;
#🎜🎜#
#🎜🎜#
반환
값;
#🎜🎜#
#🎜🎜# }#🎜🎜#
#🎜🎜# }#🎜🎜#
#🎜🎜# #🎜🎜#
#🎜🎜#
공개
V get(객체 키) {
#🎜🎜#
#🎜🎜#
return
internalMap.get(key);
#🎜🎜#
#🎜🎜# }#🎜🎜#
#🎜🎜# #🎜🎜#
#🎜🎜#
public
void
putAll(Map<?
extends
K, ?
확장
V> newData) {
#🎜🎜#
#🎜🎜#
동기화
(
이것
) {
#🎜🎜#
#🎜🎜#
Map<K, V> newMap =
new
HashMap<K, V>(internalMap);
#🎜🎜#
#🎜🎜#
newMap.putAll(newData);
#🎜🎜#
#🎜🎜#
internalMap = newMap;
#🎜🎜#
#🎜🎜#<코드> <코드>}#🎜🎜#
#🎜🎜#<코드> <코드>}#🎜🎜#
#🎜🎜#<코드>}#🎜🎜#
#🎜🎜#
#🎜🎜##🎜🎜##🎜🎜#구현은 매우 간단합니다. CopyOnWrite 메커니즘을 이해하면 다양한 CopyOnWrite 컨테이너를 구현하고 다양한 애플리케이션 시나리오에서 사용할 수 있습니다.
CopyOnWrite의 응용 시나리오
CopyOnWrite 동시 컨테이너는 더 많이 읽고 더 적게 쓰는 동시 시나리오에서 사용됩니다. 예를 들어, 화이트리스트, 블랙리스트, 제품 카테고리 액세스 및 업데이트 시나리오입니다. 검색 웹사이트가 있는 경우 사용자는 이 웹사이트의 검색창에 키워드를 입력하여 콘텐츠를 검색하지만 일부 키워드는 검색이 허용되지 않습니다. 검색할 수 없는 키워드는 블랙리스트에 등록되어 매일 밤 업데이트됩니다. 사용자가 검색할 때 현재 키워드가 블랙리스트에 있는지 확인합니다. 그렇다면 검색을 수행할 수 없다는 메시지가 표시됩니다. 구현 코드는 다음과 같습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
가져오기 java.util.Map;
🎜
🎜가져오기 com.ifeve.book.forkjoin.CopyOnWriteMap; 🎜
🎜 🎜
🎜/** 🎜
🎜 * 黑name单服务 🎜
🎜 * 🎜
🎜 * @author fangtengfei 🎜
🎜 * 🎜
🎜 */🎜
🎜공개 클래스 BlackListServiceImpl { 🎜
🎜 🎜
🎜 private static CopyOnWriteMap<String, Boolean> blackListMap = new CopyOnWriteMap<String, Boolean>( 🎜
🎜 1000 ); 🎜
🎜 🎜
🎜 공개 정적 부울 isBlackList(문자열 ID) { 🎜
🎜 return blackListMap.get(id) == null 거짓 : 참 ; 🎜
🎜 } 🎜
🎜 🎜
🎜 public static void addBlackList(String id) { 🎜
🎜 blackListMap.put(id, Boolean.TRUE); 🎜
🎜 } 🎜
🎜 🎜
🎜 /** 🎜
🎜 * 일괄적으로 블랙리스트 추가 🎜
🎜 * 🎜
🎜 * @param ID 🎜
🎜 */🎜
🎜 public static void addBlackList(Map<string> ids) {</string> 🎜
🎜 blackListMap.putAll(ids); 🎜
🎜 } 🎜
🎜 🎜
🎜}🎜
🎜
🎜🎜🎜코드는 매우 간단하지만 CopyOnWriteMap을 사용할 때 주의해야 할 두 가지 사항이 있습니다. 1. 확장 오버헤드를 줄입니다. 쓰기 중 CopyOnWriteMap 확장 오버헤드를 방지하려면 실제 필요에 따라 CopyOnWriteMap의 크기를 초기화하세요. 2. 일괄 추가를 사용하세요. 추가할 때마다 컨테이너가 매번 복사되기 때문에 추가 횟수를 줄이면 컨테이너가 복사되는 횟수를 줄일 수 있습니다. 예를 들어 위 코드에서 addBlackList 메서드를 사용합니다. CopyOnWrite의 단점CopyOnWrite 컨테이너에는 많은 장점이 있지만 메모리 사용량과 데이터 일관성이라는 두 가지 문제도 있습니다. 그래서 개발할 때 주의를 기울여야 합니다. 메모리 사용량 문제. CopyOnWrite의 쓰기 시 복사 메커니즘으로 인해 쓰기 작업이 수행되면 두 개체, 즉 이전 개체와 새로 작성된 개체가 동시에 메모리에 상주하게 됩니다(참고: 복사 중에는 쓰기 시에만 새 개체가 생성되어 새 컨테이너에 추가되지만 이전 컨테이너의 개체는 계속 사용되므로 개체 메모리의 복사본이 두 개가 됩니다. 이러한 객체가 차지하는 메모리가 비교적 큰 경우(예: 200M 정도) 여기에 100M의 데이터를 쓰면 300M의 메모리를 차지하므로 이때 Yong GC 및 Full GC가 자주 발생할 수 있습니다. 이전에는 CopyOnWrite 메커니즘을 사용하여 매일 밤 큰 개체를 업데이트하는 시스템 서비스를 사용하여 매일 밤 15초의 Full GC가 발생했으며 애플리케이션 응답 시간도 길어졌습니다. 메모리 사용량 문제를 고려하여 컨테이너의 요소를 압축하면 큰 개체의 메모리 소비를 줄일 수 있습니다. 예를 들어 요소가 모두 십진수인 경우 다음으로 압축하는 것을 고려할 수 있습니다. 16진수 시스템 또는 기본 64. 또는 CopyOnWrite 컨테이너를 사용하지 말고 ConcurrentHashMap과 같은 다른 동시 컨테이너를 사용하세요. 데이터 일관성 문제. CopyOnWrite 컨테이너는 데이터의 최종 일관성만 보장할 수 있지만 데이터의 실시간 일관성은 보장할 수 없습니다. 따라서 작성된 데이터를 즉시 읽으려면 CopyOnWrite 컨테이너를 사용하지 마십시오. 관련 기사: Java의 동시 프로그래밍: CountDownLatch, CyclicBarrier 및 Semaphore # 🎜 🎜#[JAVA 동시 프로그래밍 실습] 순차 교착 상태 잠금 관련 동영상:Java 멀티스레딩 및 동시성 라이브러리 고급 응용 프로그램 동영상 튜토리얼# 🎜 🎜# 위 내용은 Java 동시 프로그래밍: 동시 컨테이너 CopyOnWriteArrayList의 구현 원리의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요! 본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
![]() 핫 AI 도구![]() Undresser.AI Undress사실적인 누드 사진을 만들기 위한 AI 기반 앱 ![]() AI Clothes Remover사진에서 옷을 제거하는 온라인 AI 도구입니다. ![]() Undress AI Tool무료로 이미지를 벗다 ![]() Clothoff.ioAI 옷 제거제 ![]() AI Hentai GeneratorAI Hentai를 무료로 생성하십시오. ![]() 인기 기사
R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전
By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전
By 尊渡假赌尊渡假赌尊渡假赌
어 ass 신 크리드 그림자 : 조개 수수께끼 솔루션
2 몇 주 전
By DDD
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전
By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전
By 尊渡假赌尊渡假赌尊渡假赌
![]() 뜨거운 도구![]() 메모장++7.3.1사용하기 쉬운 무료 코드 편집기 ![]() SublimeText3 중국어 버전중국어 버전, 사용하기 매우 쉽습니다. ![]() 스튜디오 13.0.1 보내기강력한 PHP 통합 개발 환경 ![]() 드림위버 CS6시각적 웹 개발 도구 ![]() SublimeText3 Mac 버전신 수준의 코드 편집 소프트웨어(SublimeText3) ![]() 뜨거운 주제
Gmail 이메일의 로그인 입구는 어디에 있나요?
![]() ![]()
Cakephp 튜토리얼
![]() ![]()
Steam의 계정 이름 형식은 무엇입니까?
![]() ![]()
Win11 활성화 키 영구
![]() ![]()
NYT 연결 힌트와 답변
![]() ![]() ![]() C++의 함수 예외 처리는 다중 스레드 환경에서 스레드 안전성과 데이터 무결성을 보장하는 데 특히 중요합니다. try-catch 문을 사용하면 특정 유형의 예외가 발생할 때 이를 포착하고 처리하여 프로그램 충돌이나 데이터 손상을 방지할 수 있습니다. ![]() 동시성과 코루틴은 GoAPI 설계에서 다음을 위해 사용됩니다. 고성능 처리: 성능 향상을 위해 여러 요청을 동시에 처리합니다. 비동기 처리: 코루틴을 사용하여 작업(예: 이메일 보내기)을 비동기적으로 처리하고 메인 스레드를 해제합니다. 스트림 처리: 코루틴을 사용하여 데이터 스트림(예: 데이터베이스 읽기)을 효율적으로 처리합니다. ![]() PHP 멀티스레딩은 독립적으로 실행되는 스레드를 생성하여 하나의 프로세스에서 여러 작업을 동시에 실행하는 것을 의미합니다. PHP에서 Pthreads 확장을 사용하여 멀티스레딩 동작을 시뮬레이션할 수 있습니다. 설치 후 Thread 클래스를 사용하여 스레드를 생성하고 시작할 수 있습니다. 예를 들어, 대량의 데이터를 처리할 경우 데이터를 여러 블록으로 나누어 해당 개수의 스레드를 생성해 동시 처리함으로써 효율성을 높일 수 있다. ![]() 뮤텍스는 C++에서 다중 스레드 공유 리소스를 처리하는 데 사용됩니다. std::mutex를 통해 뮤텍스를 만듭니다. mtx.lock()을 사용하여 뮤텍스를 획득하고 공유 리소스에 대한 독점 액세스를 제공합니다. 뮤텍스를 해제하려면 mtx.unlock()을 사용하세요. ![]() 다중 스레드 프로그램 테스트는 반복 불가능성, 동시성 오류, 교착 상태 및 가시성 부족과 같은 문제에 직면합니다. 전략은 다음과 같습니다. 단위 테스트: 스레드 동작을 확인하기 위해 각 스레드에 대한 단위 테스트를 작성합니다. 멀티스레드 시뮬레이션: 시뮬레이션 프레임워크를 사용하여 스레드 일정을 제어하여 프로그램을 테스트합니다. 데이터 경합 감지: 도구를 사용하여 valgrind와 같은 잠재적인 데이터 경합을 찾습니다. 디버깅: 디버거(예: gdb)를 사용하여 런타임 프로그램 상태를 검사하고 데이터 경합의 원인을 찾습니다. ![]() 다중 스레드 환경에서 C++ 메모리 관리는 데이터 경합, 교착 상태 및 메모리 누수와 같은 문제에 직면합니다. 대책에는 다음이 포함됩니다. 1. 뮤텍스 및 원자 변수와 같은 동기화 메커니즘을 사용합니다. 2. 잠금 없는 데이터 구조를 사용합니다. 3. 스마트 포인터를 사용합니다. 4. (선택 사항) 가비지 수집을 구현합니다. ![]() 단위 테스트 동시 기능은 동시 환경에서 올바른 동작을 보장하는 데 도움이 되므로 매우 중요합니다. 동시 기능을 테스트할 때는 상호 배제, 동기화, 격리와 같은 기본 원칙을 고려해야 합니다. 동시 기능은 경쟁 조건을 시뮬레이션하고, 테스트하고, 결과를 확인하여 단위 테스트할 수 있습니다. ![]() C++ 다중 스레드 프로그래밍을 위한 디버깅 기술에는 데이터 경합 분석기를 사용하여 읽기 및 쓰기 충돌을 감지하고 동기화 메커니즘(예: 뮤텍스 잠금)을 사용하여 이를 해결하는 것이 포함됩니다. 스레드 디버깅 도구를 사용하여 교착 상태를 감지하고 중첩된 잠금을 방지하고 교착 상태 감지 메커니즘을 사용하여 교착 상태를 해결합니다. 데이터 경합 분석기를 사용하여 데이터 경합을 감지하고 쓰기 작업을 중요한 섹션으로 이동하거나 원자성 작업을 사용하여 이를 해결합니다. 성능 분석 도구를 사용하여 컨텍스트 전환 빈도를 측정하고 스레드 수를 줄이고 스레드 풀을 사용하며 작업을 오프로드하여 과도한 오버헤드를 해결합니다. ![]() |