2017-12-17 14 views
2

다음과 같은 코드로 인해 동기화 된 메소드가 만들어 지지만 객체 레벨 잠금이 발생하는 이유를 설명 할 수 있습니까? 자바 동시성을 철저히 따릅니다. 클래스 레벨을 사용하면 확실히 작동하므로 스레드마다 차지하는 잠금이 서로 다르기 때문에 설명하십시오.자바 동시성 동기화 문제

/** 
* 
*/ 
package lession2.shared.object; 

/** 
* @author so_what 
* 
*/ 

class SharedClass { 
    private static int sharedData; 

    public synchronized int getSharedData() { 
     return sharedData; 
    } 

    public synchronized void setSharedData(int sharedData) { 

     SharedClass.sharedData = sharedData; 
    } 

} 

//output of the program should be the distinct numbers 
public class StaleDataExample extends Thread { 
    static SharedClass s1=new SharedClass(); 
    static int counter=0; 
    public static void main(String args[]) throws InterruptedException { 

     StaleDataExample t1=new StaleDataExample(); 
     StaleDataExample t2=new StaleDataExample(); 
     StaleDataExample t3=new StaleDataExample(); 
     StaleDataExample t4=new StaleDataExample(); 
     StaleDataExample t5=new StaleDataExample(); 
     StaleDataExample t6=new StaleDataExample(); 
     t1.start(); 
     t2.start(); 
     t3.start(); 
     t4.start(); 

     t5.start(); 
     t6.start(); 
     t1.join(); 
     t2.join(); 
     t3.join(); 
     t4.join(); 
     t5.join(); 
     t6.join(); 
     System.out.println(); 

    } 
    public void run() 
    { 

     s1.setSharedData(s1.getSharedData()+1); //read->modify->write operation 
     System.out.print(s1.getSharedData()+" "); 
    } 

} 
+2

'// 읽기> 수정 -> 쓰기 작업'은'읽기'와'쓰기'만이 (독립적으로) 동기화됩니다. 단일 원자 조작이어야합니다. – tkausl

+0

get과 set 작업이 동일한 잠금 복합 원자량을 획득하는 경우 동일한 잠금을 획득하지 않는 이유를 정당화 할 수 있습니까? –

+0

그들은 같은 잠금을 획득하고 있습니다. 왜냐하면 다른 잠금 스레드가 개입 할 수있는 값을 전혀 수정하지 않는 타임 슬라이스가 존재하기 때문입니다. – tkausl

답변

2

여기에서 공유 값을 원자 단위 (예 : 동기화 된) 방식으로 증가시키지 않는 것이 문제입니다.

은의 다음 줄을 살펴 보자 :

s1.setSharedData(s1.getSharedData()+1) 

첫째, 당신은 새 값을 설정하는 synchronized. You then increment the value, at call setSharedData`이 getSharedData를 호출합니다. 문제는 프로그램이 get과 set 사이에서 컨텍스트 전환이 가능하다는 것입니다.

  1. 스레드 # 1 전화 getSharedData(), 0
  2. 스레드 # 2 통화 getSharedData() 얻을, 또한 0
  3. 스레드 # 1은 그 값에 1을 추가하고, setSharedData(1)를 호출 가져옵니다 다음과 같은 예를 생각해 보자.
  4. 스레드 2는 또한 값 1에 1을 더하고 예상하는 setSharedData(2) 대신 setSharedData(1)을 호출합니다. 이러한 문제를 해결하기

한 가지 방법은 원자 값을 변경 (증가) 할 때 직접 값을 설정하지만, 방법을 제공하는 클래스를 허용하지 않는 '사용자입니다 :

class SharedClass { 
    private static int sharedData; 

    public synchronized int getSharedData() { 
     return sharedData; 
    } 

    public synchronized void incrementSharedData(int amount) { 
     sharedData += amount; 
    } 
} 
+0

ohh 다른 해결책은 AtomicInteger를 사용하여 여기에서 경쟁 조건을 방지하는 것입니다. 또한 동기화 된 방법으로도 계산을 수행 할 수 있습니다. 클래스 SharedClass { \t private AtomicInteger sharedData = new AtomicInteger (0); \t public synchronized int getSharedData() { \t \t return sharedData.getAndIncrement(); \t} \t } \t 공공 무효 실행() \t { \t \t \t System.out.print (s1.getSharedData() + ""); \t} } –