代码之家  ›  专栏  ›  技术社区  ›  Prashast

信号量被多次中断的问题

  •  2
  • Prashast  · 技术社区  · 15 年前

    我有一个信号量,它限制用户一次下载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异常!!创建的任何新线程都将永远等待Acquire方法!

    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 回复  |  直到 15 年前
        1
  •  2
  •   Gregory Mostizky    15 年前

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

    相反,尝试以下方法:

        ExecutorService executorService = Executors.newFixedThreadPool(5);
        executorService.submit(new Runnable() {
            public void run() {
                // do download
            }
        });
    
        2
  •  0
  •   Sharun    15 年前

    你在释放捕获中的信号量吗?

    为什么不把试水放在蓄水层里呢?不知道Java做什么,但这不会更合乎逻辑。这样,try中的任何问题…catch总是以释放信号量结束。