2016-08-22 6 views
2

내가 읽고 있던 post on JavaCodeGeeks이 코드는 어떻게 스레드 안전합니까?

public User build() { 
    User user = new User(this); 
    if (user.getAge() > 120) { 
     throw new IllegalStateException(“Age out of range”); // thread-safe 
    } 
    return user; 
} 

public User build() { 
    if (age > 120) { 
     throw new IllegalStateException(“Age out of range”); // bad, not thread-safe 
    } 
    // This is the window of opportunity for a second thread to modify the value of age 
    return new User(this); 
} 

나는 후자는 아니지만 방법 하나는 이전의 코드가 스레드 안전하다고 말할 수있는 질문이

.

+0

getAge()는 어떻게 생겼습니까? – SomeDude

+0

@svasa 'age'가 현재 클래스의 멤버 인 경우 링크 –

+0

의 게시물을 참조하십시오. 'build'는 인스턴스 메소드입니다. –

답변

1

두 개의 스레드가 같은 같은 UserBuilder를 사용하는 경우 : build()의 스레드 구현으로

User.UserBuilder builder = new User.UserBuilder("Jhon", "Doe"); 

    // First thread 
    Thread t1 = new Thread(){ 
    @Override 
    public void run() 
    { 
     builder.age(30).build();   
    }}; 

    // Second thread 
    Thread t2 = new Thread(){ 
     @Override 
     public void run() 
     { 
      // Just changing age temporarily in builder. 
      builder.age(140); 
      builder.age(35).build();   
     }}; 

    t1.start(); 
    t2.start(); 

, 당신은 던져 질 것이다 (120) 등의 불법 주 예외보다 나이가 사용자를하지 않습니다.

두 번째 경우에 t1이 조건을 검사 할 때 age == 30이지만 이 age == 140 일 때 발생할 수 있습니다. 이 경우 예외가 없으며 연령에 대한 불변성이 깨집니다. 첫 번째 경우에는 발생하지 않습니다.

2

@AshwineeKJha가 관찰 한 것처럼이 게시물은 새 User 개체의 age 속성이 의도 한대로 유효성이 확인되는지 여부에 따라 "스레드로부터 안전합니다"라고 간주합니다. 이 속성은 final 필드를 기반으로하기 때문에 개체가 완전히 생성 된 후에 값을 읽는 스레드는 해당 속성의 최종 값을 볼 수 있습니다. 구축 전에 새로운 객체의 검증을 실시하는 대신, 구축 후에 새로운 객체의 검증을 실시하면 (자), thread 안전상의 문제를 피할 수가 있습니다.

한편, 빌더 객체가 스레드간에 공유되는 경우 하나의 스레드가 age 필드를 쓰고 다른 스레드가 age 필드를 읽으면 두 스레드 간의 동기화가 필요합니다. 이러한 이벤트 조합이 동기화없이 발생할 수있는 프로그램은 제대로 동기화되지 않습니다. 클래스/메소드와 관련하여 "스레드 안전성"의 일반적인 정의는 인스턴스가 클래스간에 공유 될 때 적절한 동기화를 보장하기 위해 클래스의 사용자가 외부 동기화를 수행 할 필요가 없다는 것입니다. 제시된 코드는 그 의미에서 쓰레드 안전하지 않습니다.

0

스레드 안전성에 대한 주석은 그 사실을 불분명하게 만듭니다.

이 기사는 여러 스레드 중 동일한 인스턴스 (builder)가 UserBuilder 인 공유 방향으로 암시하는 것 같습니다. 어쨌든 그렇게 좋은 아이디어는 아닙니다. Effective Java Item 2에 설명 된대로이 패턴의 사용을주의 깊게 코드화하고 설명하는 빌더 패턴의 주요 사용은 변경 불가능한 클래스의 일관된 인스턴스를 작성하는 동안 텔레 스코핑 생성자를 피하는 것입니다.

User 불변 (클래스 final 경우) (따라서 스레드 안전)하지만 UserBuilder이 아닌 (따라서 안전 나사)를 참고. 그리고 그것은 의도적으로 설계된 것입니다. 아이디어는 빌더 인 thread-unsafe 클래스를 통해 User 클래스의 일관된 인스턴스를 생성하는 것입니다. 따라서 빌더를 사용하기 전에주의를 기울여야하며 스레드간에 공유하는 것에 대해 편집증이 있어야합니다.

여러 스레드에서 빌더를 공유해야하는 경우, 거기에 제안 된 사항이 적절할 수 있습니다. 제안은 지역 변수의 스택 감금 아이디어에 피기 백합니다. 변수 user은이를 생성 한 스레드에 의해서만 나타나는 로컬 변수입니다. 그렇게하면 스레드를 안전하게 사용할 수 있습니다.두 번째 구현은 UserBuilder이라는 스레드 안전하지 않은 특성을 미묘하게 호출하여 문제를 일으 킵니다.

일반적으로 User이라는 새 인스턴스를 build 메소드에 반환하고 개별 체크를 빌더에 제공된 setters에 남기는 것이 좋습니다. 그리고 예, 스레드간에 빌더 인스턴스를 신중하게 공유하십시오. Effective Java Item 2를 참조하십시오.

관련 문제