2009-12-10 112 views
1

我正在創建一個包含一些動態生成圖像的網頁。如果需要的話等待結果

在我的頁面請求處理中,我創建了所有圖像並將它們存儲在內存緩存中,直到它們隨後被瀏覽器請求。

public class CachedImage 
{ 
    byte[] data; 
    Date created; 
} 

目前,我的圖片緩存基本上是HashMap<Integer, CachedImage>

問題是,圖像生成需要時間,並且我想在所有圖像完成生成之前開始渲染頁面。

所以我想生成一個線程池中的圖像,並在請求時返回數據,如果它已準備就緒或等待數據準備好然後返回。

任何人都可以拿出這個機制的整潔模型?

圖像很小,我很高興現在在內存中緩存整個圖像的方法。

回答

2

在生成頁面時,爲頁面顯示的每個圖像選擇一個新的唯一標識符。這可能簡單得像是通過遞增AtomicInteger獲得的數字,或者它可能更像UUID那樣複雜,以防止用戶猜測其他用戶的圖像URL。將這些唯一標識符放入客戶端用來檢索圖像的URL中。

一旦您選擇了圖像的標識符,構建一個Callable將生成並返回圖像,並將其提交到ThreadPoolExecutor以異步運行。這給你一個Future可以用來檢索結果。將未來保存在地圖中,並將圖像的標識符作爲關鍵字。

後來,當客戶端請求的圖像,你可以把圖像標識,並期待它在地圖上找到相關的未來目標。在Future上調用get()將返回圖像,並在必要時等待發生器完成。 (如果在地圖中找不到所請求的標識符,返回404錯誤。)

爲了避免填滿服務器的舊影像的存儲,你可能會想,幾分鐘後丟棄它們。爲此,每次創建任務並將其Future放入可用圖像的地圖中時,都可以將任務放入DelayQueue中,該任務將在適當延遲後從地圖中移除條目。使用守護進程線程從該隊列中取得項目,並在循環中對其執行操作。

這也將會是一個好主意,從地圖中刪除它時,萬一發電機仍在運行出於某種原因調用cancel(true)於未來。 (否則它會繼續運行,即使圖像將不再是可訪問的反正。)

+0

幾乎我現在得到的。 – pstanton 2009-12-10 05:51:00

0

你可以從當前請求刪除整個邏輯與異步請求(AJAX),這甚至可以讓你有一個「正在載入」圖標,並控制超時和這樣

+0

好主意,但對圖像的渲染參數的複雜性使得很難去耦合的單個圖像。我已經做出了這樣一個呼籲,即一代人需要在一點上初始化,並且必須堅持下去。 – pstanton 2009-12-10 04:55:16

0

當渲染圖像客戶端(瀏覽器)請求一個網頁,但實際上當時並沒有獲取圖像。當它呈現頁面並找到標籤時,瀏覽器會將每個圖像的不同請求發回服務器。這意味着您可以在圖像存在之前發送HTML頁面。

因此燒掉你的HTML響應,發送圖像創建請求到你的圖像服務。瀏覽器解析響應並從Web服務器請求圖像。

您可以通過讓另一個線程池通過接受單個線程中的請求來響應圖像請求,並在圖像準備就緒時做出響應,從而使它更上一層樓。如果您只是儘可能快地生成圖像,並讓網絡服務器響應圖像請求,則您的用戶將獲得404個尚未生成圖像的響應。

+0

你錯過了這一點,但謝謝。 – pstanton 2009-12-10 05:10:24

1

聽起來像是你需要像futuretask東西

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Future.html

剛剛推出了一羣人,你可以拉回來,結果當isDone是真實的,你甚至可以在等待他們完成封鎖簡單地調用get()。

+0

已經遠遠更加適應現在一個線程池 – pstanton 2009-12-10 05:38:25

+0

結合這一點,因爲圖像的一半是由時間上的瀏覽器的頁面加載就緒,該解決方案比其他兩個建議的方式更快。 – pstanton 2009-12-10 05:42:06

+0

我會雙倍upvote如果我可以,但wyzard提供更多的信息。你讓我在正確的道路上,謝謝。 – pstanton 2009-12-10 10:39:31