2012-05-17 3 views
2

Java의 Semaphore 클래스를 사용하여 작성된 다음과 같은 동시성 코드는 콘솔 출력에 따라 교착 상태가되며 심지어는 허가가 해제됩니다.허가가 해제 되더라도 Semaphore 클래스가 교착 상태에 들어갈 수 있습니까?

package ThreadTraining; 

import java.util.concurrent.Semaphore; 

public class ThreadTraining { 

    public static class Value { 

     private static int value = 0; 
     private static final Semaphore SEMAPHORE = new Semaphore(1); 

     public static synchronized void acquire() throws InterruptedException { 
      SEMAPHORE.acquire(); 
      System.out.println("A thread has aquired a permit!"); 
     } 

     public static synchronized void release() { 
      SEMAPHORE.release(); 
     } 

     public static int get() { 
      return value; 
     } 

     public static void add() { 
      value++; 
     } 

     public static void subtract() { 
      value--; 
     } 
    } 

    public static class Adder extends Thread { 

     public Adder(String name) { 
      this.setName(name); 
     } 

     @Override 
     public void run() { 
      System.out.println(this.getName() + " has been created."); 
      boolean keepRunning = true; 
      while (keepRunning) { 
       try { 
        Value.acquire(); 
        System.out.print(this.getName() + " has aquired Value's permit. --- "); 
        if (Value.get() > 99) { 
         System.out.print(this.getName() + " has finished it's job. --- "); 
         keepRunning = false; 
        } else { 
         System.out.print(this.getName() + " has modified value from " + Value.get() + " to "); 
         Value.add(); 
         System.out.println(Value.get() + "."); 
        } 
       } catch (InterruptedException ie) { 
        System.err.println("This thread was interrupted."); 
       } finally { 
        System.out.println(this.getName() + " is releasing Value's permit."); 
        Value.release(); 
       } 
      } 
     } 
    } 

    public static void main(String[] args) { 
     Thread threads[] = new Thread[3]; 
     for (int i = 0; i < threads.length; i++) { 
      threads[i] = new Adder("[Adder]Thread #" + i); 
     } 
     for (Thread t : threads) { 
      t.start(); 
     } 
    } 
} 

코드의 콘솔 출력 :

[Adder]Thread #0 has been created. 
[Adder]Thread #1 has been created. 
[Adder]Thread #2 has been created. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 0 to 1. 
[Adder]Thread #0 is releasing Value's permit. /*NOTE: It usually prints only up to this line, hanging after the first permit-release.*/ 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 1 to 2. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 2 to 3. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 3 to 4. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 4 to 5. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 5 to 6. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 6 to 7. 
[Adder]Thread #0 is releasing Value's permit. 
A thread has aquired a permit! 
[Adder]Thread #0 has aquired Value's permit. --- [Adder]Thread #0 has modified value from 7 to 8. 
[Adder]Thread #0 is releasing Value's permit. 

뒤에 이유가 무엇입니까 (이것은이 "운"를 실행, 그것은 보통 지정된 시점까지 인쇄했다)? 가능한 경우 어떻게 수정해야합니까?


추가 정보 :

이 질문은 my previous concurrency question의 "계속"입니다.

새 코드는 매우 this semaphore tutorial을 기반으로합니다.

답변

4

문제는 자신의 방법을 동기화하는 것입니다. 두 Value.acquireValue.release 동기화됩니다, 그래서 release 전화가 출시 될 Value -class의 모니터 대기하므로 acquire 내부의 하나가 내부 세마포어를 기다리는 동안 하나 개의 스레드는, 당신의 acquire -method이 release 전화에서 다른 하나를 차단합니다 입력 획득 될 메소드에서 synchronized - 키워드를 제거하면 교착 상태 문제가 제거됩니다. 대신, 당신은 아마도 get -, add - 및 subtract - 방법을 동기화하려고했습니다.

+0

음, \ aquire() 메소드에서 \ [synchronized \]를 제거하지 않으면 여러 스레드가 동시에 호출 할 수있는 기회를 만들 수 있습니까? 나는 released() 메소드에서만 삭제했고, 효과가있는 것으로 보인다. – XenoRo

+0

'세마포어'의 획득은 (여러분의 경우 1에서) 획득 할 수있는 최대 수만 허용하므로 여러 스레드가'acquire' 메소드를 동시에 호출하는지 여부는 중요하지 않습니다. 다른 스레드는 필요한 양의 허가가 사용 가능할 때까지 차단합니다 (한 번에 둘 이상의 허가를 취득 할 수있는 세마포어 획득에 과부하가 있음). 세마포어에 하나의 허가 만 허용하고 있기 때문에 뮤텍스와 유사하게 작동합니다. 자세한 내용은 http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html#acquire%28%29를 참조하십시오. – esaj

+0

세마포어의 내부 메커니즘이 스레드 경합 시나리오를 허용 할 수 있다고 걱정됩니다. 예를 들어, 세마포어 (내부적으로)가 "더 이상 취득 할 수 없도록"설정하기 전에 두 번째 스레드 (내부적으로)가 첫 번째 스레드에 의해 이미 획득 된 허가를 획득하는 경우. 이 문제 이전의 마지막 질문은 그러한 시나리오의 좋은 예를 제공합니다 (그리고 결과물에서의 결과입니다). 아마 힘든 경우는 아닙니다. – XenoRo

관련 문제