2012-09-05 3 views
4

는 다음 코드를 고려하십시오 필드를 휘발성으로 선언해야합니까?

class Foo { 
    java.util.Timer timer = new java.util.Timer(); 

    void doAction() { 
     ... 
     timer.schedule(new SomeTimerTask(), 0L); 
     ... 
    } 

    void cancelAction() { 
     timer.cancel(); 
    } 
} 

방법

가 다른 스레드에서 호출된다. 메소드 doAction()이 먼저 호출됩니다.

다른 스레드에서 timer 필드 volatile을 표시해야합니까?

답변

6

그것의 더 나은 당신은

volatile 키워드는 각 스레드에 휘발성 필드를 반영 해이 설명 된 바와 같이 꽤 많은 역할을 ... doAction()timer 변수 인스턴스의 중요한 상태를 조작하는 것을 cacelAction() 같은 방법에 synchronized 키워드를 사용 , 은 모든 개별 조작에만 적용되며 모든 조작에 대해 집합 적으로 적용되지는 않습니다.

+0

@RuslanZagirov 휘발성 (Volatile)은 모든 잠금에 관여하지 않고 스레드에 동시 액세스를 제공하지만 키워드 동기화는 개체에 대한 잠금을 획득하여 리소스를 잠급니다. 이제는 다른 스레드가이 리소스에 액세스 할 때까지 스레드가 개체 잠금을 얻었습니다, 그것을 풀어 ... 그때 다른 스레드가 잠금을 얻을 ... 지금 여기이 스레드는 이전 스레드에 의해 변경된 필드의 값을 참조 ..... –

+1

그러나이 경우 타이머의 작업은'synchronized' 블록에서 실행하지 않아도됩니다. 왜냐하면 javadoc은 스레드로부터 안전하다고 말하기 때문입니다. –

0

필드를 volatile로 선언하지 않아도 모든 스레드에서 볼 수 있습니다. 변수와 연관된 volatile 키워드는이 변수가 다중 스레드에 의해 잠재적으로 수정되므로 로컬로 캐시해서는 안됨을 Java 런타임에 지시합니다.

3

필드를 휘발성으로 만들 필요가 없습니다. 왜냐하면 어느 스레드도 필드 자체를 변경하지 않기 때문입니다. 값은 이니셜 라이저에서 한 번 설정되고 이후에는 변경되지 않습니다.

메서드에 동기화를 추가해야하지만이 경우에는 변수 volatile을 선언하는 것이 완전히 필요하지 않습니다. final을 사용하는 것이 훨씬 더 적합합니다.

+0

알다시피, 다른 스레드에 대한 업데이트를 전파해야하는 경우 모든 필드가 휘발성을 선언해야합니다. 휘발성 키워드가 없으면 개체 필드는 개체와 상호 작용하는 모든 스레드에서 볼 수 있지만 일부 스레드는 필드 값을 로컬로 캐시 할 수 있습니다. 옳은? –

+0

@RuslanZagirov - '휘발성'이이 작업을 수행하는 유일한 방법이 아니라는 점에서 사용자의 이해가 올바르지 않습니다. –

+0

@RuslanZagirov 'timer'의 값이 로컬로 캐시 된 경우에도 로컬 캐시의 모든 복사본은 'Timer'객체의 동일한 인스턴스를 가리킬 것입니다. 값이 변경되지 않기 때문에 참조를 한 번 캐시하고 다시는 절대 만지지 않아도됩니다. – dasblinkenlight

0

필드를 volatile으로 만들 필요는 없지만 synchronized 메서드를 사용하는 것이 더 좋습니다.

public void synchronized doAction(){} 

public void synchronized cancelAction(){} 
2

타이머 클래스 volatile가 충분한 것으로 timer 선언, 그 javadoc 따른 따라서

스레드 안전하다. timer이 (경우에 나타납니다으로) 다른 곳에서는 할당되지 않은 경우

그러나,하는 더 나은 솔루션final로 필드를 선언하는 것입니다. 이는 동기화를 수행하지 않고 timer 변수를 여러 스레드에서 안전하게 사용할 수 있도록하기에 충분합니다.

Timer가 스레드로부터 안전하지 않은 경우 동기화 된 메서드 나 블록 (또는 Locks 등을 사용하여 구현 된 동등한 함수)에서 Timer 인스턴스에 대한 모든 작업을 수행해야합니다 (자세한 내용은 JLS Section 17.5을 참조하십시오) . timervolatile 또는 final으로 선언하는 것으로는 충분하지 않습니다.

+0

한 스레드에서 타이머 필드를 업데이트하면 다른 스레드에 대한 업데이트 전파에 volatile 필드가 필요합니다. 기본적으로 업데이트되지 않으면 모든 스레드에서 정확한 필드 값을 사용할 수 있습니다. 옳은? –

+0

올바르지 않습니다. 그것은 '타이머'가 업데이트 되더라도 그것을 수행하는 유일한 방법은 아닙니다. (5 개의 답변 중 4 개가 명시 적으로 명시하고 5 번째는 반대하지 않습니다!) –

+0

+1 타이머 코드를 체크하면'schedule()'과'cancel()'메소드가 동기화되어 외부 동기화를 추가하는 지점이 없습니다 . –

관련 문제