2015-05-07 19 views
2

我有,我必須實現一個接口命名打印所使用框架的Web應用程序:如何使用ThreadLocal(特別是與Servlets)?

interface Plot { 
    Image getImage(); 
    String getTitle(); 
} 

我知道框架調用getTitle()getImage()。在某些情況下,我需要圖像生成的結果來創建標題。

我知道,如果我做了什麼天真這樣的:

class MyNaivePlot implements Plot { 
    private String title; 

    public Plot getImage() { 
    title = "..."; 
    } 

    public String getTitle() { return title; } 
} 

然後,我可以介紹的競爭條件。看來我可以通過使用ThreadLocal來解決這個問題,但我還沒有看到足夠的例子來知道我的解決方案是否正確(並且這些類型的東西很難以確定的方式進行測試)。所以這裏是我想出的:

class MyThreadLocalPlot implements Plot { 
    private ThreadLocal<String> title = new ThreadLocal<String>(); 

    public Plot getImage() { 
    title.set("..."); 
    } 

    public String getTitle() { 
    return title.get(); 
    } 
} 

這是否足夠?我正確使用ThreadLocal嗎?請注意,我只需要將標題掛起足夠長的時間,直到getTitle()爲止。我不在乎它之後的價值是什麼,也不在getImage()之前。

另請注意,我相信框架「長命」了MyPlot對象,並且不會爲每個請求/線程創建一個新對象,否則這將是一個非問題。

謝謝!

+0

這個類是如何調用的?它是爲每個請求instanciated?或只是一次? – chburd

+0

*然後我可以介紹一個競賽條件*:你能詳細說明一下嗎?你有多少個這個班的實例?他們是如何創建的?他們如何以及爲什麼在線程之間共享? –

+0

你的線程局部變量應該是靜態的最後 – Scorpion

回答

1

你的代碼很正確;你沒有一個setter方法,但我想有一個錯字,而不是getImage你想寫setTitle()。 threadLocal還有一個remove方法,您應該在不再需要title屬性時調用該方法。您可以找到一些使用示例herehere

在部署基於ThreadLocal的Plot版本之前,我建議您檢查您的框架是否創建一個或多個實例;只需使用計數器創建一個regolare類並在get方法中增加計數器值;您可以記錄它以查看計數器值如何隨不同呼叫而改變。如果您使用日誌框架(如log4j或logback),則建議將線程名稱放入日誌中,以便檢查計數器值是如何/是否隨不同檢查而更改。

我也建議你同時測試多個客戶端,如果你有一個「串行客戶端」,如果你使用的是專用測試實例,最終可能會使用相同的服務器線程。

+0

謝謝,我會在那裏添加一個remove()。關於確認只有一個實例的好建議;我幾乎肯定這是事實。正如我所提到的,我已經嘗試過測試我的解決方案是否可行,但由於使用了線程池,所以它很棘手。它似乎工作正常,但只是想確認我沒有錯過任何東西。再次感謝! – rjcarr

2

要直接回答你的問題 - 這聽起來沒問題。然而,我會考慮一些額外的要點:

(1)如果你有一個開始/結束請求的鉤子 - 你可能想在每個這樣的請求結束時清除本地線程(例如,如果它是一個servlet我會使用一個過濾器)。這是由於兩個原因:釋放它的垃圾收集和錯誤的情況下(如果下一個請求遇到一些解析錯誤,它會看到一個空的圖像,而不是以前的用戶)。 (2)確保你的框架在這​​兩個請求期間確實保證了一個線程(和同一臺機器)。也許還要檢查它是否能用於即將推出的版本以及水平縮放/集羣。

(3)作爲附註,也可以考慮其他解決方案 - 例如,緩存(這可以幫助你作爲副作用)。顯然這需要一些雖然緩存大小,定期清除/更新等。

+0

感謝您的信息;我可以添加一個remove()到最後。我保證這兩種方法都是用同一個線程調用的。再次感謝! – rjcarr