2010-04-18 4 views
64

의 Java Concurrency 책을 읽었습니다. 15 장에서는 논 블로킹 알고리즘과 비교 교환 ( (CAS)) 방법에 대해 설명합니다.자바 동시성 : CAS 대 잠김

CAS는 잠금 방법보다 훨씬 뛰어나다 고 기록되어 있습니다. 나는 이미이 두 가지 개념을 가지고 일했던 사람들에게이 개념들 중 어느 것을 선호하는지 듣고 싶습니다. 정말 빨라요?

내게는 잠금 장치 사용이 훨씬 명확하고 이해하기 쉽고 을 유지하는 것이 더 좋습니다 (내가 틀렸다면 수정하십시오). 더 나은 성능 향상을 위해 잠금보다 CAS와 관련된 동시 코드를 만드는 데 중점을 두어야합니까? 아니면 지속 가능성이 더 중요합니까?

나는 무엇을 사용할 때 엄격한 규칙이 아닐지도 모른다. 하지만 저는 새로운 개념의 CAS에 대한 의견과 경험을 듣고 싶습니다.

답변

37

CAS는 일반적으로 잠금보다 훨씬 빠르지 만 경합의 정도에 따라 다릅니다. 읽기와 비교 사이의 값이 변경되면 CAS가 재 시도를 할 수 있기 때문에 문제의 변수가 다른 많은 스레드에 의해 심하게 눌려 지거나 (또는 ​​값이 비싸다면) 스레드는 이론 대기 상태에서 멈춘 상태가 될 수 있습니다 이전 값 (또는 둘 다)에서).

CAS의 주요 문제는 잠금보다 올바르게 프로그래밍하는 것이 훨씬 어렵다는 것입니다. Locking은 메시지 전달 또는 STM보다 올바르게 사용하는 것이 훨씬 어렵 기 때문에 자물쇠 사용에 대한 강력한지지로 삼지 마십시오.

+0

나는 새로운 가치를 계산하기 위해 * 비용을 들인다는 것에 동의한다. 대개 너무 커서 잠금을 사용하지 않는 전략이 잠금 기반으로 손실됩니다. –

16

ConcurrentLinkedQueue와 BlockingQueue 사이의 숫자를 볼 수 있습니다. CAS가 보통 (실제 응용 프로그램에서는 좀 더 현실적인) 스레드 컨 텐션에서 눈에 띄게 빠르다는 것을 알 수 있습니다.

논 블로킹 알고리즘의 가장 매력적인 특성은 한 스레드에서 오류가 발생하면 (캐시 ​​미스 또는 오류가 발생하는 경우) 다른 스레드가이 오류를 인식하지 않고 계속할 수 있다는 것입니다. 그러나 잠금을 획득 할 때 잠금 보유 스레드에 일종의 OS 장애가 있으면 잠금을 해제 할 때까지 기다리는 다른 모든 스레드가 실패로 인해 충돌합니다.

질문에 답하기 위해 비 차단 스레드 안전 알고리즘 또는 콜렉션 (ConcurrentLinkedQueue, ConcurrentSkipListMap/Set)은 해당 블록킹 대응 항목보다 상당히 빠를 수 있습니다. 마르셀로 (Marcelo)가 지적했듯이, 논 블로킹 알고리즘을 올바로 수정하는 것은 매우 어렵고 많은 고려가 필요합니다.

Michael and Scott Queue에 대해 읽어야합니다. ConcurrentLinkedQueue의 대기열 구현이며 단일 CAS로 양방향 스레드 안전 원자 함수를 처리하는 방법을 설명합니다.

+1

"Michael and Scott Queue"에 대한 기사가 흥미 롭습니다. 고마워! – Prine

12

이 강하게 잠금이없는 동시성의 주제와 관련된 좋은 책이있다 : 작업의 모리스 헐리 히

+0

또한 그의 프레젠테이션 [파트 1] (http://research.microsoft.com/apps/video/default.aspx?id=168298) 및 [파트 2] (http://research.microsoft.com/apps/video /default.aspx?id=169831) 매우 가치가 있습니다. –

23

의 상대 속도에 의해 "멀티 프로세서 프로그래밍의 예술"은 대부분 아닌 문제입니다. 관련된 것은 잠금 기반 알고리즘과 비 차단 알고리즘 간의 확장 성의 차이입니다. 1 또는 2 코어 시스템에서 실행중인 경우 그런 일에 대해 생각해보십시오.

비 차단 알고리즘은 일반적으로 잠금 기반 알고리즘보다 더 짧은 "임계 섹션"을 가지기 때문에 확장 성이 좋습니다.

5

실제 비교를 원하시면 여기를 클릭하십시오. 우리의 어플리케이션은 2 개의 스레드를 가지고 있습니다. 1) 네트워크 패킷 캡처를위한 판독기 스레드와 2) 패킷을 가져 와서 통계를보고하는 소비자 스레드.

스레드 # 1 교류 스레드 번호와 한 번에 하나의 패킷을 2

결과 # 1 - 우리 클래스 CASSynchronousQueue라고 에 SynchronousQueue와 동일한 원리를 사용하여 사용자 CAS 기반 교환을 사용 :

30,766,538 packets in 59.999 seconds :: 500.763Kpps, 1.115Gbps 0 drops 
libpcap statistics: recv=61,251,128, drop=0(0.0%), ifdrop=0 

결과 # 2 - 우리는 표준 자바 우리의 CAS 구현을 대체 S ynchronousQueue는 :

8,782,647 packets in 59.999 seconds :: 142.950Kpps, 324.957Mbps 0 drops 
libpcap statistics: recv=69,955,666, drop=52,369,516(74.9%), ifdrop=0 

나는 성능의 차이가 더 이상 명확하지 않을 수 있다고 생각하지 않습니다.