변수의 동기화 및 로컬 사본
-
13-09-2019 - |
문제
다음 관용구가있는 레거시 코드를보고 있습니다.
Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (myMap) {
item = myMap.get(myKey);
}
Intelli-J의 코드 검사에서 얻은 경고는 다음과 같습니다.
Synchronization on local variable 'myMap'
이것이 적절한 동기화입니까?
Map<String, Boolean> myMap = someGlobalInstance.getMap();
synchronized (someGlobalInstance.getMap()) {
item = myMap.get(myKey);
}
해결책
이것이 문제로 표시되는 이유는 로컬 변수의 동기화가 일반적으로 나쁜 생각이기 때문입니다.
만약에 물체가 반환되었습니다 someGlobalInstance.getMap()
항상 동일합니다. 그런 다음 동기화 된 블록은 실제로 준 글로벌 객체 모니터를 사용하고 코드는 예상 결과를 생성합니다.
또한 동기화 된 래퍼를 사용하라는 제안에 동의합니다. get()
/put()
호출 및 더 큰 동기화 된 블록이 없습니다. 그러나지도가 있는지 확인하십시오 뿐 래퍼를 통해 액세스하거나 버그에 대한 또 다른 기회가 있습니다.
또한 someGlobalInstance.getMap()
하다 ~ 아니다 동일한 객체를 항상 반환하면 두 번째 코드 예제조차 제대로 작동하지 않으며 호출하는 것과 다른 객체와 동기화 할 수 있기 때문에 원래 코드보다 더 나빠질 수 있습니다. get()
에.
다른 팁
getMap () 메소드가하는 일에 따라 코드가 소리가 될 수 있다고 생각합니다. 스레드간에 공유 해야하는 인스턴스에 대한 참조를 유지하면 의미가 있습니다. 로컬 변수가 로컬로 초기화되지 않으므로 경고는 관련이 없습니다.
사용하는 것이 더 좋을 것이라고 생각합니다 동기화 된 래퍼 지도를 위해
알렉스는 호출하여 동기화 된 래퍼를 추가하는 것이 맞습니다. Collections.synchronizedMap(Map)
여기서 전형적인 접근법입니다. 그러나이 접근 방식을 취하면 여전히 동기화 해야하는 상황이있을 수 있습니다. Map
의 자물쇠; 예를 들어지도를 반복 할 때.
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<String, String>());
// Synchronized on map to prevent ConcurrentModificationException whilst iterating.
synchronized (syncMap) {
for (Map.Entry<String, String> entry : syncMap.entrySet()) {
// Do work
}
}
예를 들어, 아이디어로부터의 경고는 로컬 변수가 분명히 분명히 무시할 수 있습니다. map
다른 곳에서 검색됩니다 (someGlobalInstance
) 방법 내에서 생성되기보다는 다른 스레드에서 잠재적으로 액세스 할 수 있습니다.