2013-08-03 3 views
5

코드 - 1동기화 액세스

class RequestObject implements Runnable 
{ 
    private static Integer nRequests = 0; 

    @Override 
    public void run() 
    {  
     synchronized (nRequests) 
     { 
      nRequests++; 
     } 
    } 
} 

코드 - 2

class RequestObject implements Runnable 
{ 
    private static Integer nRequests = 0; 
    private static Object lock = new Object(); 

    @Override 
    public void run() 
    {  
     synchronized (lock) 
     { 
      nRequests++; 
     } 
    } 
} 

두 번째 코드는 어떤 경쟁 조건을 일으키지 않고 잘 작동하는 동안, 먼저 동일한 클래스 (RequestObject)의 서로 다른 인스턴스간에 정적 데이터 멤버에 대한 액세스를 동기화하는 데 성공하지 못합니다. 누군가 더 많은 빛을 던질 수 있을까요? 왜 첫 번째 접근 방식이 작동하지 않는지 이해하고 싶습니다.

원본 구현이 첫 번째 구현입니다. 나중에 나는 https://stackoverflow.com/a/2120409/134387에서 보았다.

+3

'정수'는 변경 불가능하기 때문에. 당신이 생각하는대로 증가시키지 않고있다. –

+1

도 정수를 사용하지 않고,'int'를 사용한다. –

+0

이것은 다른 질문이다. 새로운 질문으로 만드십시오. –

답변

6

지속적으로 새로운 Integer 개체를 만들고 동기화 한 다음 최소한 생각하면 혼란 스럽습니다. 그래서 다음과 같은 시나리오를 얻을 수 있습니다 :

스레드 A가 nRequests의 현재 값으로 유지됩니다를 (같은 값 (0)

스레드 A가 증가 nRequests을위한

스레드 B 큐 (0 말할 수 있습니다) 값 1로)

스레드 C는 새 값을 가져 와서 동기화하고, 값을 늘리고 값을 버립니다.

스레드 A는 B가 0에 동기화하고 모두가 가지고 하나의 개체가 두 번째 방법으로 C

의 변경 내용을 덮어 1로 증가 0

실에서 모니터로 갈 수 에 동기화하십시오. 정확히 당신이 원하는 것입니다.

4

Integer의 인스턴스는 변경 불가능하므로 nRequests++ 개체는 결과를 보유 할 Integer 개체를 새로 만들고 nRequests에 저장합니다. synchronized 문은 개체에 동기화됩니다. 따라서 스레드는 서로 다른 개체에서 동기화됩니다. 예, 같은 개체의 동기화 된 블록에는 동시에 하나의 스레드 만있을 수 있지만 서로 다른 스레드가 서로 다른 개체의 동기화 된 블록에 동시에있을 수 있습니다 ...

액세스를 동기화하는 가장 쉬운 방법은 정적 상태는 정적 동기화 방법에 넣어된다

static synchronized void increment() { 
    nRequests++; 
} 

이것은 다음의 동기화 블록에 상당 :

synchronized (RequestObject.class) { 
    nRequests++; 
} 

을 RequestObject 정적 필드를 포함하는 클래스이다.

2

문제는 Integer 클래스가 java에서 불변이라는 것입니다. 따라서 각 스레드는 nRequests++이 각 호출에서 새 오브젝트를 작성하기 때.에 다른 오브젝트에서 동기화됩니다.

두 번째 경우 lock 개체는 모든 인스턴스에 대해 동일하며 스레드의 액세스를 nRequests 변수로 성공적으로 직렬화합니다.

관련 문제