Collections.synchronizedMap()
에서 잠금의 차이와 ConcurrentHashMap
이다 스레드 X가 Collections.synchronizedMap()
에있는 메서드를 호출하면 스레드 X가 호출 한 메서드에서 반환 할 때까지 다른 모든 스레드는 Collections.synchronizedMap()
에있는 메서드를 호출 할 수 없게됩니다.
ConcurrentHashMap
에는 ConcurrentHashMap
에있는 키 세그먼트를 보호하는 다양한 수의 잠금 장치 (기본값은 16)가 있습니다. 160 키를 가진 ConcurrentHashMap
의 경우 각 잠금은 10 개의 요소를 보호합니다. 따라서 키 (get
, put
, set
등)에서 작동하는 메서드는 키가 동일한 세그먼트에있는 키에서 작동하는 다른 메서드에 대한 액세스 만 잠급니다. 예를 들어 스레드 X가 put(0, someObject)
을 호출하고 스레드 Y가 put(10, someOtherObject)
을 호출하면 해당 호출이 동시에 실행될 수 있으며 스레드 Y는 스레드 X가 put(0, someObject)
에서 반환 될 때까지 기다릴 필요가 없습니다. 다음은 그 예입니다.
또한 size()
및 isEmpty()
과 같은 특정 방법은 전혀 지키지 않습니다. 이는 동시성을 높이는 반면, 일관성이 강하지 않다는 것을 의미합니다 (동시에 변경되는 상태는 반영하지 않습니다).
public static void main(String[] args) {
ConcurrentHashMap<Integer, Object> map = new ConcurrentHashMap<>(160);
new Thread(new Runnable() {
@Override
public void run() {
map.put(0, "guarded by one lock");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
map.put(10, "guarded by another lock");
}
}.start();
new Thread(new Runnable() {
@Override
public void run() {
// could print 0, 1, or 2
System.out.println(map.count());
}
}.start();
}
오케이, 이해합니다. 하지만 두 개 이상의 스레드가 {0,63}의 하위 배열에서 모두 수정하려고하면 어떻게됩니까? – GedankenNebel
그러면 처음으로 첫 번째로 제공됩니다. 잠금을 획득하는 첫 번째 스레드가 변경되며, 두 번째 스레드가 완료되면 두 번째 스레드가 변경됩니다. 'ConcurrentHashMap'는'replace'와 같은 메소드를 가지고있어서 두번째 쓰레드가 첫번째 쓰레드의 변경을 우연히 덮어 쓰지 않도록합니다. –
나는 실제로 "선착순"이라고 생각하지 않는다. (나는 정확한 인용문을 가지고 있지 않지만 실제로 Java Concurrency in Practice에서 배웠다.) 공정성은 생성자에서와 같이 명시적일 때만 보장된다. 'ReentrantLock'이나'ArrayBlockingQueue'와 같은 대기열과 같은 다른 명시적인'Lock' 구현물에 대해서. (이전 스레드 인 것을 알고 있습니다. 미안합니다.) – Marcelo