2013-05-31 24 views
0

我試圖編寫一個算法,下載視頻直播流。具體而言,我試圖獲取的相應數據流基於一個動態的播放列表文件,該文件定期提供新視頻文件的URI。主要目標是將這些單獨的媒體文件組合成一個連貫的InputStream。
我確實成功地實現了它的工作:我定期檢查播放列表中出現的新媒體文件,並將它們的HTTP流傳遞給自定義InputStream實現,即InputStreamChain。由於它是一個直播流,我認爲它至少在目前是無盡的。埃爾戈,我想我的InputStreamChainread()永遠不會發送-1。不幸的是,它確實;每當所有排隊的媒體流被消耗時,InputStreamChain就結束了。相反,我希望它阻止I/O,直到一個新的媒體文件到達。 所以,我想出了一個工作解決方案:我調整了read()方法以循環,直到有新的可用流(TimerTask將提供新文件)。在循環中,我建一個Thread.sleep(),以降低CPU的負荷:InputStream中的塊I/O讀取()

public int read() throws IOException { 
    int bit = current.read(); 
    if (bit == -1 && streams.size() > 0) { 
     // left out due to lacking relevance 
    } else if(bit == -1 && streams.size() == 0) { 
     while(streams.size() == 0) { 
      Thread.currentThread().sleep(50); 
     } 
     return read(); 
    } 
    return bit; 
} 

雖然它似乎工作,我有一種感覺,那我不這樣做,我應該如何。我也嘗試過使用LockCondition.await(),但是當我的TimerTask試圖觸發Condition.signal()時,它只是拋出了IllegalMonitorStateException
這就是爲什麼我問的問題

以何種方式,我應該延遲/阻塞的InputStream的read()方法,尤其是在我的情況?

編輯:

爲了完整起見,我將提供我的失敗Lock的做法,太:

private ReentrantLock ioLock; 
private Condition ioCond; 
private boolean waitingForStream = false; 

public InputStreamChain() { 
    ioLock = new ReentrantLock(); 
    ioCond = ioLock.newCondition(); 
} 

public synchronized InputStreamChain addInputStream(final InputStream stream) { 
    streams.addLast(stream); 
    if (current == null) { 
     current = streams.removeFirst(); 
    } 
    if(waitingForStream) { 
     ioCond.signal(); 
    } 
    return this; 
} 

public int read() throws IOException { 
    int bit = current.read(); 
    if (bit == -1 && streams.size() > 0) { 
     // do stuff 
    } else if(bit == -1) { 
     waitingForStream = true; 
     ioLock.lock(); 
     try { 
      ioCond.await(); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } finally { 
      waitingForStream = false; 
      ioLock.unlock(); 
     } 
     return read(); 
    } 
    return bit; 
} 
+0

您必須獲取鎖定以發出信號並等待條件。 – Flavio

+0

@Flavio我從頭頂寫下了自己的'Lock'方法。我哪裏做錯了? – MCL

+0

你必須在'cond.signal()'之前調用'lock.lock()',然後''lock.unlock()'。 – Flavio

回答

1

也許你不使用synchronized塊。以下是一個示例:

class MyReader 
{ 
    public int read() throws IOException { 
     int bit = current.read(); 
     if (bit == -1 && streams.size() > 0) { 
      // left out due to lacking relevance 
     } else if(bit == -1 && streams.size() == 0) { 
      waitForNextStream(); 
      return read(); 
     } 
     return bit; 
    } 

    private synchronized void waitForNextStream() 
    { 
     // TODO add close handling, set current here 
     while (streams.isEmpty()) 
     { 
      wait(); 
     } 
    } 


    public synchronized void addNextStream(InputStream is) 
    { 
     streams.add(is); 
     notify(); 
    } 
} 
+0

謝謝Valeri!看起來不錯。我假設,在我的情況下,我必須在'addInputStream()'方法內部放置'notify()'。 +1現在...我會盡快測試它。 – MCL

+1

@MCL不要忘記'synchronized'塊。沒有它們,它就無法工作。 –

+0

好的,我按照你的建議實現了它,它完美地工作。無論如何,我有一些問題:1.爲什麼你在循環中包裝'wait()'?根據文檔,'wait()'無論如何都會等待下一個'notify()'。我試過了,它也沒有循環。 2.我讀到,InputStreams有一些特殊的IO阻塞方法,但無法找到它的含義。這是說的方式,還是有其他的可能性? – MCL

相關問題