2012-08-16 5 views
1

스레드 안전성

다스 위에 긴 포함 정적 방법 (하여 멀티 스레드 애플리케이션을 고려 ... perpertual "긴-IF 또는 스위치" 딜레마의 변형 조건) 따라 값을 객체의 유형을 확인하고 반환 if 문,

public static String checkType(Class<?> type) 
{ 
    if (type == A.class) 
    { 
     return aString; 
    } 
    else if (type == B.class) 
    { 
     return bString; 
    } 
    ... 
    else if (type == z.class) 
    { 
     return zString; 
    } 
} 

같은 즉, 뭔가 분명히 스위치 문은 매우 일반적인 패턴은 enum을 가지고 호출하는 것입니다, 여기에 직접 적용 할 수 없습니다 그 valueOf(), 즉 d O 따라서

public enum Strings 
{ 
    A(aString), B(bString), ..., Z(zString) 

    private final String value; 

    private Strings(String value) 
    { 
     this.value = value; 
    } 

    public String value() 
    { 
     return this.value; 
    } 
} 

같은는 checkType()getActualTypeName()있어서 내부 생산 코드 및 비 - 프리미티브 타입 일부 문자열 처리 첨가 null 값에 대한 적절한 검사와

public static String checkType(Class<?> type) 
{ 
    return Strings.valueOf(getActualTypeName(type.getClass().getName())).value(); 
} 

로 다시 쓸 수있다 "class java.lang.Long"과 같은 문자열에서 실제 형식 이름을 검색하려면 (예 : getName() 메서드는 예상되는 문자열을 반환합니다. valueOf()는 스레드로부터 안전하지 않습니다 경우 "long"는).

그러나,이 동시 환경에서 작동하지 않습니다. 같은가 (정상) Map 객체와 아마이 두 가지 대안이 같은 패턴의 변형은을 사용하여 적용, enum.valueOf() 때문에 분명히 Class.java 클래스

enumType.enumConstantDirectory().get(name); 

를 호출

Enum.valueOf(Class<T> enumType, String name) 

을 기반으로합니다.

,

enumConstantDirectory() 메서드는 호출 할 때마다 values() 배열 복사본에서 만든 HashMap을 반환합니다.

스레드 안전할까요?

답변

4

enum.valueOf(String)는 스레드 안전하지 왜 나는 어떤 이유를 찾을 수 없습니다 :

  • 문자열은 불변이므로 인수가 변이 될 수 없다 valueOf이 일을하면서
  • valueOf 인수 대를 확인 . 열거 형 상수의 이름은 모두 정적이고 최종적인 것입니다.

enum.valueOf()은 스레드로부터 안전하지 않다는 생각이 들게합니까?

편집

valueOf 호출 : enumType이 열거 형 클래스이다

T result = enumType.enumConstantDirectory().get(name); 

.

  • 경우 enumConstantDirectory은 :

    private volatile transient Map<String, T> enumConstantDirectory = null; 
    

    그 방법에 동시에 도착 스레드를 상상해 enumConstantDirectory는 휘발성 변수가

    Map<String, T> enumConstantDirectory() { 
        if (enumConstantDirectory == null) { 
         T[] universe = getEnumConstantsShared(); 
         if (universe == null) 
          throw new IllegalArgumentException(
           getName() + " is not an enum type"); 
         Map<String, T> m = new HashMap<>(2 * universe.length); 
         for (T constant : universe) 
          m.put(((Enum<?>)constant).name(), constant); 
         enumConstantDirectory = m; 
        } 
        return enumConstantDirectory; 
    } 
    

    :

    enumConstantDirectory()이 패턴을 사용하여 null (휘발성이기 때문에 여기에 가시성 문제가 없음), c 맵을 onstruct하고 해당 변수에 할당하십시오. 불안정한 보증이 있기 때문에 그 시점부터 다른 모든 스레드는 완전히 구성된 맵을 볼 수 있습니다.

  • 다른 스레드가 동시에 방법에 도착하고도 enumConstantDirectory의 null 값을 관찰하면, 그것은지도를 다시 그리고 여기에 안전하게 최악의 시나리오는 그 두 스레드가 잠재적으로 할 수있다

다시 게시합니다 2 개의 다른지도 (다른 경우)를 사용하고 있지만 내용은 동일하므로 문제가 발생하지 않습니다.

결론 : 맵 구조가이 인구가되었습니다 후 휘발성 변수 에 할당 된 지역 변수에 수행되므로 스레드가 절반 구성되어지도를 볼 수있는 방법은 없습니다 .

+0

Enum.valueOf() , 비동기지도를 찾습니다. Enum.valueOf() 메서드의 소스를 살펴보십시오. enumType.enumConstantDirectory(). get (name)을 호출합니다. – PNS

+1

@PNS 더 자세히 살펴보면'enumConstantDirectory' (변수)가 휘발성임을 알 수 있습니다. 따라서지도가 안전하게 게시되고 구성 후 변경되지 않도록 충분히 보장 할 수 있습니다. 최악의 경우는 맵이 두 번 이상 생성되지만 최종 상태를 기반으로 작성되므로 결정적이므로 사용되는 지연 패턴을 사용하면 스레드를 안전하게 유지할 수 있습니다. – assylias

+0

당신 말이 맞아요, 안전 할 것 같습니다. 어느 것이 좋니! :-) – PNS

3

Enum.valueOf()이 스레드로부터 안전하지 않다고 가정 할 이유가 없습니다. 아무것도 변이시키지 않으며 실제 최종 상태 인 실제 enum 클래스의 상태에만 액세스합니다.

이 스레드가 아닌이면 javadocs에 뭔가가 있다고 생각합니다.

+0

Enum.valueOf()를 확장하면 비 동기화 된 맵을 찾습니다. Enum.valueOf() 메서드의 소스를 살펴보십시오. enumType을 호출합니다.enumConstantDirectory(). get (name). 동기화되지 않은지도의 – PNS

+3

조회는 읽기 전용 인 경우 완벽하게 안전합니다. 지도가 안전하게 게시 된 경우에만 – stevevls

+1

@stevevls. – assylias

1

은 내가 잘못 될 수 있지만, 여기에 미묘한 문제가있는 것 같다

public static <T extends Enum<T>> T valueOf(Class<T> enumType, 
                 String name) { 
    T result = enumType.enumConstantDirectory().get(name); 
    if (result != null) 
      return result; 
    if (name == null) 
      throw new NullPointerException("Name is null"); 
    throw new IllegalArgumentException(
        "No enum constant " + enumType.getCanonicalName() + "." + name); 
} 

이 valueOf에 대한 코드가. enumType에 전달 된을 사용하여 상수가있는 HashMap 내부를 만들고 코드는 sychronized이 아닙니다. T result = enumType.enumConstantDirectory().get(name);
enumConstantDirectory()enumConstantDirectory == null에 대한 검사를 수행하지만이 HashMap을 만들기 위해, 동기화되지 않은 :
여기에 미묘한 문제가 발생한 것 같습니다. 아마도 부작용은 중요하지 않습니다. (어떤 정보가 Class에 저장되어 있는지는 알 수 없습니다.) 어쨌든 enumType이 응용 프로그램 코드에서 공유되지 않는 한 확실합니다.

+0

필자는 그렇게 생각하지 않는다 :'enumConstantDirectory()'는 IMO가 안전하게 공개되었음을 보증하는 휘발성 변수를 사용하여 느리게 생성된다. – assylias

+1

@assylias : 내가 틀렸을 수도 있지만 가시성 만 보장합니까? 동기화 보증이 없습니다 – Cratylus

+1

수정 된 답변보기, 맞습니다. 따라서 맵은 두 번 이상 생성 될 수 있고 2 개의 스레드는 서로 다른 맵 인스턴스를 볼 수 있지만 모든 스레드는 올바른 맵 (올바른 키/값을 포함)을 준수합니다. – assylias