2009-08-04 3 views
2

사용자가 한 번에 n 개의 파일을 다운로드하도록 제한하는 세마포가 있습니다. 각 파일은 별도의 스레드에 다운로드됩니다.세마포어가 여러 번 중단되는 문제

편집가 : 이전 다운로드 한 번 세마포어의 모든 허가를 구입하기 완료 될 때까지 방출이 제대로

import java.util.concurrent.Semaphore; 
public void downloadFile() { 
    Thread downloadThread = new Thread() { 
     boolean bSemaphoreAcquired = false; 
     public void run() { 
      try { 
       semaphore.acquire(); 
       bSemaphoreAcquired = true; 
       // do the download 
      } catch (InterruptedException e) { 
      } finally { 
       if (bSemaphoreAcquired) semaphore.release(); 
      } 
     } 
    }; 
    // add download thread to the list of download threads 
    downloadThread.start(); 
} 

발생 있도록 예제를 수정, 새로운 다운로드 기다립니다.

사용자가 획득 호출에서 대기중인 다운로드를 취소하도록 선택하면 해당 다운로드 스레드를 종료하기 위해 interrupt() 메서드를 호출합니다. 내가 직면 한 문제는 일단이 세마포어가 중단 되었다면 두 번째로 InterruptedException 예외를 던지지 않을 것입니다 !! 생성 된 새로운 쓰레드는 획득 메소드를 영원히 기다릴뿐입니다!

Sequence of events (Semaphore that permits 2 threads) 
- thread 1 downloading 
- thread 2 downloading 
- thread 3 waiting on acquire() 
- thread 3 is cancelled (interrupt() is called). InterruptedException is thrown and the thread exits 
- thread 4 is created and is now waiting on acquire() 
- thread 4 is cancelled (interrupt() is called). InterruptedException IS NOT THROWN ANYMORE!!! 

Semaphore$FairSync(AbstractQueuedSynchronizer).fullGetFirstQueuedThread() line: 1276  
Semaphore$FairSync(AbstractQueuedSynchronizer).getFirstQueuedThread() line: 1232  
Semaphore$FairSync.tryAcquireShared(int) line: 201 
Semaphore$FairSync(AbstractQueuedSynchronizer).acquireSharedInterruptibly(int) line: 1142 
Semaphore.acquire() line: 267 
FileDownloadManager$1.run() line: 150 

스레드 4의 스택 트레이스는 왜 스레드 4하지 예외를받을 않습니다입니까?

+1

이이 문제에 도움이되지 않습니다,하지만 당신은이 할 필요가있는 경우에는 세마포어 누출이 없도록는, 최종적으로 블록에 "해제"를 호출 놓아야 대신

같은 것을 시도 예외는 다운로드 중입니다. – Thilo

+0

세 번째로 중단하면 어떻게됩니까? "획득"을 기다리고 있습니까? 그걸 확인하기 위해 JVM 스레드 덤프 (kill -QUIT)를 얻을 수 있습니까? – Thilo

+0

새로운 스레드는 모두 획득시 대기 상태를 유지하고이 상태에 도달하면 중단 될 수 없습니다. 이제 원래의 쓰레드 1과 쓰레드 2가 실행을 끝내고 세마포어를 릴리즈하더라도 새로운 쓰레드는 acquire()를 무한정 기다리게된다 !! 질문에 스택 추적을 추가했습니다. – Prashast

답변

2

나는 세마포어 대신 표준 스레드 풀을 사용할 것을 제안합니다. 솔루션의 문제점은 최대 한계에 도달했는지 여부에 관계없이 새 스레드를 만드는 것입니다. 따라서 1000 개의 동시 요청이 있다면 1000 개의 스레드를 생성하게되어 낭비입니다.

ExecutorService executorService = Executors.newFixedThreadPool(5); 
    executorService.submit(new Runnable() { 
     public void run() { 
      // do download 
     } 
    }); 
+1

감사합니다. 그건 내 문제를 해결. 내 세마포어 솔루션으로 무슨 일이 일어나고 있는지 궁금합니다. – Prashast

+0

@Prashast : 실제로 다른 스레드를 방해 할 가능성이 있습니까? –

+0

아니요, 나는 정확한 스레드를 방해하고 있다고 확신합니다. 코드를 단계별로 여러 번 확인했습니다. – Prashast

0

catch 내에서 세마포를 해제 하시겠습니까?

aquire-release 내에 try-catch를 두지 마십시오. 자바가하는 일은 확실하지 않지만 더 논리적이지는 않을 것이다. 그런 식으로 try ... catch 내의 모든 문제는 항상 릴리스되는 세마포로 끝납니다.

+1

거기서 세마포어를 풀어 봤지만 도움이되지 않는다. 여전히 같은 행동을한다. 또한이 함수에는 다른 예외가 throw되지 않습니다. 유일하게 가능한 것은 acquire()에 의해 Throw 된 InterruptedException입니다 (그리고 스레드가 처음에 그것을 결코 얻지 못할 때 세마포어를 해제해야한다고 생각합니다). – Prashast

+1

@Prashast : 네, 맞습니다. 당신은 당신이 결코 얻지 못했던 세마포어를 결코 "릴리즈"하지 말아야한다 (당신이 이상한 종류의 로직을 구현하지 않는다면). – Thilo