2012-09-13 2 views
1

두 스레드 (주 스레드 및 모니터 스레드)간에 개체가 공유되는 코드는 아래와 같습니다. MyObject를 전역으로 선언하고 메모리에 푸시되도록 volatile으로 설정해야합니까? 그렇지 않으면 if 문은 MyObject가 스레드에 의해서만 로컬로 액세스되고 휘발성으로 선언되지 않으면 "Not null"을 인쇄 할 수 있습니까?휘발성 키워드 : 두 스레드간에 동기화되는 변수입니까?

public static void main(String[] args) { 
    MyObject obj = MyObjectFactory.createObject(); 
    new Monitor(obj).start(); 
    Thread.sleep(500); 
    if(obj == null) 
     System.out.println("Null"); 
    else 
     System.out.println("Not null"); 
} 

public void doSomethingWithObject(MyObject obj) { 
    obj = null; 
} 

private class Monitor extends Thread { 
    public Monitor(MyObject obj) { 
     this.obj=obj; 
    } 
    public void run() { 
     doSomethingWithObject(obj); 
    } 
} 

참고 :이 코드 예제는 내가 Stackoverflow에서 작성한 이후로 컴파일되지 않을 수 있습니다. 의사 코드와 실제 코드가 혼합 된 것으로 간주하십시오.

+0

컴파일하는 코드 예제로 시연하고 싶은 것을 말하기가 훨씬 쉬울 것입니다. – Affe

+0

@Affe : 죄송합니다. 왜 내가 컴파일 할 수 없는지 설명하는 게시물에 메모를했습니다. :-) – Rox

답변

2

인스턴스는 공유되지만 인스턴스에 대한 참조는 공유되지 않습니다. 예 :

String a = "hello"; 
String b = a; 

b = null; // doesn't affect a 

ab가 동일한 인스턴스에 대한 참조; 하나의 참조를 변경해도 동일한 인스턴스에 대한 인스턴스 또는 다른 참조에 영향을 미치지 않습니다. 당신이 스레드 간의 상태를 공유하려면

그래서, 당신은 volatile 수이 MyObject 내부 필드 을 만들어야합니다 : volatile 단지 일부 유형의 작동

class MyObject { public volatile int shared; } 


public void doSomethingWithObject(MyObject obj) { 
    obj.shared = 1; // main() can see this 
} 

하는 것으로 (참조 및 long을 제외한 모든 프리미티브). 잘못 입력되기 쉽기 때문에 java.util.concurrent.atomic의 유형을 살펴 봐야합니다.

[편집] 위 내용이 정확하지 않습니다. 대신 을 long과 함께 사용하면 Java 5 이상에서 예상대로 작동합니다. 이 유형의 원자 읽기/쓰기를 보장하는 유일한 방법입니다. 참조를 위해이 질문을보십시오 : Is there any point in using a volatile long?

명성 그걸 지적하기 위해 Affe로 가십시오. 감사.

+0

휘발성에 관한 참조는 오랫동안 작동하지 않습니까? O_o – Affe

+0

@Rox는 바이트 크기와 상관없이 기본 변수에만 적용됩니다. – alfasin

+0

'volatile'은 작동하지만 읽거나 쓰지 않아 예기치 않은 결과가 발생할 수 있습니다. http://stackoverflow.com/questions/3038203/is - 어떤 - 포인트 -에서 - 사용 - 휘발성 - 긴 –

1

개체를 원자 적으로 읽기 - 업데이트 - 쓰기 스키마로 이동하려면 volatile이 개체를 자르지 않습니다. 동기화를 사용해야합니다.

휘발성은 변수가 현재 스레드에 캐시되지 않지만 변수가 동시에 업데이트되지 않도록합니다. 따라서 변수가 예기치 않게 변경 될 수 있습니다.

IBM의 developerWorks의 제목은 a useful article입니다.

+0

감사합니다, 기사를 읽을 것입니다! – Rox

1

예제는 Monitor이라는 하나의 스레드로만 구성되며 main()에서 생성되어 실행됩니다.

"메모리에 푸시 될 수 있도록 변경해야합니까?" - 반대로 변수를 volatile으로 선언하면 스레드 로컬 메모리에 "밀어 넣기"(캐시되지 않음) 보장되므로 변수 값을 변경하는 다른 스레드가있을 수 있습니다.

당신이 방법 doSomethingWithObject (에 메소드의 서명을 변경) 동기화해야 변수의 올바른 값을 인쇄 있는지 확인하기 위해서 :

public synchronized void doSomethingWithObject(MyObject obj) 

또는 주변 동기화 블록을 만들 :

obj = null; 

this.obj=obj; 
1

당신은 오히려 것 if 체크 전에 오브젝트를 동기화하여 null으로 설정되도록하십시오. 휘발성으로 만 설정하면 다른 스레드가 즉시 변경 내용을 볼 수 있지만 doSomethingWithObject 호출 전에 if 확인이 실행될 가능성이 높습니다.

관련 문제