2010-08-11 4 views
3

지금 자바 스레딩에 대해 자세히 배우려고하고 있는데, 나는 작은 질문을 가지고 어디서나 직접 대답을 찾을 수 없습니다. 이 코드의 해봐요 섹션에있을 때스레드 및 잠금에 관한 질문

public class FooA implements Runnable 
{ 
    Object data; 

    public FooA(final Object newData) 
    { 
     data = newData; 
    } 

    public void doSomething() 
    { 
     synchronized(data) 
     { 
      data = new Integer(1); 
     } 
    } 

    public void run() { 
     // Does stuff 
    } 
} 

public class FooB implements Runnable 
{ 
    Object data; 

    public FooB(final Object newData) 
    { 
     data = newData; 
    } 

    public void doSomething() 
    { 
     synchronized(data) 
     { 
      System.out.println(data); 
     } 
    } 
} 

겠습니까으로 fooA 블록으로 fooB : 내가 두 주 threadsthat 객체를 두 가지가 있다고 가정하자? 혹은 그 반대로도? 내 직감은 예라고하지만 책에 따르면 나는 그것을 읽고있다. 따라서 모니터 객체가 필요합니다. 약간 더 복잡한 버전을 만들었고 모든 것이 잘 작동했습니다.

약간 둘러 보았지만 구체적인 답을 찾을 수 없었습니다.

답변

2

동기화 된 블록 중 하나가 data에 새 개체를 할당하는 것이 문제입니다. 해당 블록이 처음 시작되어 data으로 변경되면 이후 실행시 다른 개체를 사용하여 잠금 상태가됩니다. 그래서 그때부터 둘 다 동시에 실행할 수 있습니다.

+0

:

나는이 책을 읽고 권하고 싶습니다? – UberJumper

+0

FooA가 다른 객체를 가리키고 있다면, 데이터 항목에 새로운 값을 할당함으로써 FooB는 결코 알지 못하며 알 필요도 없습니다. 이것은 문제가되지 않습니다. – djna

+0

@uberjumper - 데이터가 * 불변 *일까요? 'data'에 새로운 객체가 할당되어 있지 않으면 (즉,'data' 필드 자체는 변이되지 않습니다), 두 객체 모두'data' 필드에 할당 될 동일한 객체로 생성됩니다. 그렇다면 양쪽 모두 제대로됩니다. '데이터'에 동기화 될 때마다 서로를 차단합니다. –

0

같은 개체에서 동기화해야하는 한 올바른 것이지만 하나의 스레드가 "데이터"에서 참조하는 개체를 수정하기 때문에 "this"에서 동기화해야합니다.

+0

스레드 중 하나만이 초기 공유 값에서'data'를 수정하는 것처럼 보입니다. –

1

이 경우 대답은 '예'지만 취성이 있습니다 (즉 코드의 다음 변경으로 인해 문제가 발생할 수 있음). 왜 작동합니까?

FooB 결코 FooA은 (FooA는 참조 새 값을 할당 할 때 각 스레드 그래서, FooB 결코 통지를 자신의 참조를 가져옵니다) 객체를 변경한다는 통지하지 않기 때문에.

그런 경우에는 두 개의 스레드가 동일한 개체에 액세스 할 수 있고 누구나 언제든지 해당 참조를 업데이트 할 수 있고 다른 스레드는 업데이트 후에 만 ​​새 값을 가져 오는 것이 좋습니다 AtomicReference을 사용하는 것이 좋습니다.

1

모든 Java Object를 동기화에 사용할 수 있습니다.

FooA와 FooB가 모두 동일한 객체에 대한 참조를 사용하여 생성 된 경우 동일한 "잠금"객체를 공유하고 예상대로 차단됩니다. 좋은 또는 당신이 뭘 하려는지에 따라 나쁜 일 수 있음 -

Object data; 

decalrations은으로 fooA 또는으로 fooB, 또는 둘 모두가 데이터에 다른 값을 할당 한 다음 다른 개체에 동기화 될 수 중 최종되지 않는 한 . 그들은 같은 인스턴스를 초기화하지 않는

Object o = new Object(); 
FooA fooA = new FooA(o); 
FooB fooB = new FooB(o); 

, 그들은 같은 객체없는, 누군가가 같은과 같은를 초기화하지 않는 한 코드 샘플에서

1

, fooA.datafooB.data는 같은 객체 아니다 오직 같은 유형과 이름.

FooAnew Integer(1)data으로 할당하면 다시 같은 개체가 아닌 동일한 유형 및 이름이됩니다. 그래서 그 후, 그들은 당신이 필요하지 않은 경우 동기화되지 않습니다 :

fooB.data = fooA.data; 

이 동기화 실행을 보장하기 위해 동기화 블록 내부 일어날 것이다.

스레딩에 대해 알아야 할 점은 모든 것이 한 번 작동하더라도 프로그램이 올 바르거나 매번 작동한다는 것을 의미하지는 않습니다. 스레딩 문제는 타이밍이 올바르게 작동하는 경우에만 발생합니다 (또는 잘못 된 경우).

3

이 예제에는 몇 가지 문제가 있습니다.

먼저 synchronized(data)은 그 시간에 data에있는 개체에서 동기화한다는 것을 의미합니다. 두 객체를 같은 객체로 초기화했다면 동기화를 얻어야합니다.

그러나 코드 내에 data 자체를 설정하고 있기 때문에 (이후 동일한 객체가 아니기 때문에) 실제로는 그 이후에는 작동하지 않습니다.

final의 생성자 매개 변수에는 특히 유용하지 않습니다. 필드 자체의 수정 자로 더 유용 할 것입니다. 이 특정 예제에서는 값을 수정하기 때문에 작동하지 않지만 일반적으로 값이 고정 될 때 일부 동시성 문제를 방지하는 좋은 방법입니다.

좀 더 복잡한 버전 을 만들었고 모든 것이 잘 동작했습니다.

시행 착오를 통해 동시성 문제를 디버깅하는 것은 매우 어렵거나 거의 불가능합니다. 실패하지 않는다고해서 안정적으로 작동한다는 것을 의미하지는 않습니다. 그들은 각각의 모든 시간을 차단하는 것, 데이터가 가변 인 경우 http://www.javaconcurrencyinpractice.com/

+0

+1 "시행 착오를 통해 동시성 문제를 디버깅하는 것은 매우 어렵거나 거의 불가능합니다." 일반적인 퍼징 (fuzzing) 기술로도 동시성 문제가 발생하지는 않습니다. (프로덕션으로 롤아웃하고 고사양 데모 ...) –