信号量被多次中断的问题

时间:2009-08-04 08:06:14

标签: java multithreading

我有一个信号量限制用户一次下载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没有收到异常?

2 个答案:

答案 0 :(得分:2)

我建议使用标准线程池而不是信号量。 您的解决方案的问题是无论您是否达到最大限制,都会创建一个新线程。因此,如果您有1000个并发请求,您将创建1000个线程,这真的很浪费。

而是尝试这样的事情:

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

答案 1 :(得分:0)

你是否在捕获中释放了信号量?

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