2009-08-04 36 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!!! 

这是线程4

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未收到异常?

+1

这不符合您的问题有所帮助,但你应该把“释放”调入finally块,所以不存在信号泄漏是否应该有一个下载时出现异常。 – Thilo 2009-08-04 08:20:41

+0

如果第三次打断它会怎么样?你确定它在等待“获得”吗?你能得到一个JVM线程转储(kill -QUIT)来确保这一点吗? – Thilo 2009-08-04 08:35:48

+0

所有新线程都会一直等待获取,一旦达到此状态就不会中断。现在,即使原始线程1和线程2完成执行并释放信号量,新线程仍然无限期地等待acquire()!将堆栈跟踪添加到问题中。 – Prashast 2009-08-04 08:44:22

回答

2

我会建议使用标准线程池而不是信号量。 解决方案的问题在于,无论您是否达到最大限制,您都会创建一个新线程。所以,如果你有1000个同时请求,你将创建1000个线程,这是非常浪费的。

而是尝试这样的事:

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

您是否在捕获内释放信号量?

为什么不把try-catch放在aquire-release中。不确定java是做什么的,但不会更合乎逻辑。这样,try ... catch中的任何问题总是以释放的信号量结束。