2015-01-23 2 views
0

클래스의 메서드에 대한 상호 액세스를 제공해야하므로 한 스레드가 메서드 내에서 코드를 실행할 수 있습니다. 아래의 솔루션을 시도했지만 왜 'locked'변수의 값이 false인지 이해할 수 없습니다.자바 메서드에서 상호 스레드 제외

public class MyCommand extends BaseCommand { 
    private static boolean locked=false; 

    @Override 
    public boolean execute() throws Exception { 
    synchronized(MyCommand.class){ 
     while (locked){ 
      wait(); 
     } 
     locked=true; 

     //some code with a breakpoint/long blocking operations 

     locked=false; 
     notifyAll(); 
     return true; 
    } 
} 

while 문에 처음에 중단 점을 넣었고 locked 변수의 값이 항상 false이며 이유를 이해할 수 없습니다. 두 번째 중단 점은 메서드 본문에 있으며 첫 번째 스레드의 실행을 차단하고 두 번째 스레드에서 변수의 값이 변경된 것을 확인하기 위해 사용하지만 불행히도 이러한 일은 발생하지 않습니다. 따라서, 최종 결과로서 모든 스레드는 스레드 안전성없이이 메소드를 실행할 수 있습니다. 누구나 시간당 스레드 하나만이 메서드에 단독 액세스를 제공 할 수있는 방법에 대한 아이디어가 있습니까?

+0

this.class 인을 유효한 표현식이 아닙니다. 고쳐주세요. – aioobe

+0

공유 할 수있는 데이터가 없다면 명령은 스레드로부터 안전합니다. 그렇게하는 방법? 참조 매개 변수의 상태를 수정하지 마십시오. 변경할 수있는 클래스 멤버 변수를 만들지 마십시오. 왜 그냥 synchronized 키워드를 추가 할 수 없습니까? – duffymo

+3

'locked' 정적 필드는 필요 없습니다. 'syncronized (MyCommand.class)'로 충분합니다. – kraskevich

답변

3

한 번에 하나의 스레드 만 동기화 된 블록 안에 있습니다. 맞습니까? 블록 시작 부분에서 스레드를 중지하고 locked 값을 확인하십시오. 글쎄, 귀하의 스레드가 블록 안에 있다면, 그것은 다른 스레드가 없다는 것을 의미합니다. 그리고 내부에 다른 스레드가없는 경우 locked을 false로 설정해야합니다. 왜 당신을 놀라게합니까? 전체 "잠금"코드 주위 synchronized 잠금을함으로써 달성 -

당신은 바로 위에서 설명한 이유로 방식 (또는 그 문제에 대한 전체 locked 것)에 의해 while(locked) wait() 루프가 필요하지 않습니다.

+0

감사합니다 디마, 당신을위한 또 다른 질문은 내가 블록 내부 동기화 (MyClass.class) {} 내부에서 상호 배제를 달성 것으로 나타났습니다,하지만 내가 블록을 제거하고 내가 메서드 선언에 동기화 넣어 이유를 이해할 수 없다 (public synchronized boolean execute()) 일이 멈추고, 그 이유를 아십니까? – daniele

+0

@ daniele 아니요, 왜 그런지 모르겠지만 ... "물건"이 무엇인지, 어떻게 "일하"를 기대하는지에 대해 좀 더 자세히 알아보고 싶다면 뭔가 생각할 수도 있습니다. 그들이 "작업을 멈 추면"정확히 무슨 일이 발생합니까 : – Dima

+0

내가 동기화 블록 (synchronized (MyClass.class) {int a = 1;} 내에서 명시 적으로 정의 된 블록을 가지고있는 경우) 내가 줄에 중단 점을 추가하면 명령 int a = 1; 블록의 실행이 상호 배타적이기 때문에 중단 점이 하나의 스레드를 인터럽트합니다 (그리고 그것은 내가 예상했던 것입니다.).) – daniele

1

한 번에 하나의 스레드 만 동기화 된 블록을 실행하므로 값은 항상 false입니다. 첫 번째 스레드가 변수를 끝내면 변수가 다시 거짓이어서 ... 다음 스레드는 false를 읽습니다. 나는이 시나리오에서 선호

는 ReentrantLock와 같은 것을 사용 :

protected final ReentrantLock myLock= new ReentrantLock(); 

... 

try { 
     //wait until i have the lock 
     this.myLock.lock(); 

     //do some stuff 


    } finally { 
     //release the lock 
     this.myLock.unlock(); 
    } 

을 그리고이 문서에서 당신은 동기화 섹션과 ReentrantLock와 사이의 성능에서 큰 차이를 볼 수 있었다 : http://lycog.com/concurency/performance-reentrantlock-synchronized/

+0

성능은 ReentrantLock의 사용을 검증하지 않습니다. 동기화는 ReentrantLock보다 더 효과적으로 최적화 할 수있는 내장 구성 요소입니다. 또한 ReentrantLock과 비교하여 Java 5부터 동기화 처리량이 크게 증가했으며 더 빨라질 것으로 예상됩니다. 마지막으로, ReentrantLock을 사용하려면 try/finally 블록이 필요합니다.이 블록은 코드를 끔찍하고 장황하게 보이게하고 상용구 코드로 만듭니다. – xTrollxDudex