您好,登錄后才能下訂單哦!
本篇內容主要講解“Java程序的臟數據問題實例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java程序的臟數據問題實例分析”吧!
臟數據(Out-of-date data),指過時的數據。
如果在您的Java程序中存在臟數據,將或多或少地給軟件系統帶來一些問題,如:無法實時地應用已經發生改變的配置,軟件系統出現一些莫名其妙的、難以重現的、后果嚴重的錯誤等等。盡量避免臟數據的存在是非常有價值的。本文希望能在這方面給同行們一點幫助。
Fragment 1. 緩存技術的臟數據問題
/**
* A report printer is used to print a report.
*
* @version 1.0 9/9/2003
* @author Bill
*/
public class ReportPrinter {
/**
* Constructs a ReportPrinter
instance.
*/
public ReportPrinter() {
// do something...
}
/**
* Prints a printable.
*
* @param printable the specified printable object
*/
public void print(Printable printable) {
Graphics g = getGraphics();
g.setFont(getReportFont(printable.getFont());
printable.print(g);
}
/**
* Returns the corresponding report font of a java font.
*
* @param javaFont the specified java font
* @return the corresponding report font
*/
private Font getReportFont(font javaFont) {
Font reportFont = fontMap.get(javaFont);
if(reportFont == null) {
reportFont = loadFont(javaFont);
fontMap.put(javaFont, reportFont);
}
return reportFont;
}
/**
* Loads the corresponding report font of a java font.
*
* @param javaFont the specified java font
* @param the corresponding report font
*/
protected static Font loadFont(Font javaFont) {
Font reportFont = null;
// do something...
return reportFont;
}
/**
* The font map(java font->report font).
*/
private static HashMap fontMap = new HashMap();
}
Fragment 1中,由于裝載一個java font所對應的report font開銷較大,使用了緩存技術來避免這種開銷。這是一種常見的提高性能的方式,而且在一般情況下運行良好。但是Fragment 1的設計與實現可能是不完備的,因為極有可能一個java font所對應的report font在系統啟動之后發生變化,在這種變化發生之后,只有重啟軟件系統才能裝載之,這常常是最終用戶的抱怨之一。更可怕的是,類似的這種臟數據的存在還可能帶來其它嚴重的、無法想象的后果。
如何避免使用緩存技術所帶來的臟數據問題呢?
在設計、實現和測試時,應該清晰定義緩存數據的更新:
i. 不考慮緩存數據的更新,重啟軟件系統是一種必要的方式;
ii. 不考慮緩存數據的更新,緩存數據不可能成為臟數據(但在軟件系統中,往往“不可能”會在一次又一次的重構之后變為“可能”);
iii. 考慮緩存數據的更新,當源數據變化時,實時更新緩存數據。
Fragment 2. Singleton模式的臟數據問題
/**
* A storage usage handler is used to query the storage usage of users.
*
* @version 1.0 9/9/2003
* @author Bill
*/
public class StorageUsageHandler {
/**
* Returns a StorageUsageHandler
instance.
*
* @return the single StorageUsageHandler
instance
*/
public static StorageUsageHandler getStorageUsageHandler() {
if(handler == null) {
handler = new StorageUsageHandler();
}
return handler;
}
/**
* Constructs a StorageUsageHandler
instance.
*/
private StorageUsageHandler() {
users = Context.getAllUsers();
}
/**
* Returns the storage sizes of all the users.
*
* @return the storage sizes
*/
public long[] getSizes() {
long sizes[] = new long[users.size()];
for(int i = 0; i < users.size(); i++) {
sizes[i] = getOneSize(users.get(i));
}
}
/**
* Returns the storage size of a user.
*
* @param user the specified user
* @return the storage size
*/
protected long getSize(User user) {
// do something...
return 0;
}
/**
* The StorageUsageHandler
singleton.
*/
private static StorageUsageHandler handler;
/**
* The users.
*/
private List users;
}
您看出了問題所在嗎?
Fragment 2中,由于沒有必要次次實例化StorageUsageHandler而帶來不必要的開銷,采用了Singleton模式以保證StorageUsageHandler只被實例化一次。
在實例化SotrageUsageHandler時,StorageUsageHandler的類成員users將被賦值。由于不存在任何對users重新賦值的方法,一直駐留在軟件系統中的users將不會發生任何變化。在軟件系統啟動之后,增加、刪除或修改用戶的操作經常會發生,而一旦發生這類操作,users就成為了臟數據,Fragment 2將無法正常工作。
如何避免使用Singleton模式所帶來的臟數據問題呢?
對于Singleton類的類成員:
i. 對于與Singleton類外部無依賴關系的類成員,不存在這種問題;
ii. 對于依賴于Singleton類外部的類成員,且該類成員不存在更新機制,最好是將其去掉,需要時從Singleton類外部直接獲取;如果這種辦法不可行,應提供機制以確保在使用該類成員之前,該類成員已經被更新過。
Fragment 3. 類使用的臟數據問題
/**
* A storage usage handler is used to query the storage usage of users.
*
* @version 1.0 9/9/2003
* @author Bill
*/
public class StorageUsageHandler implements AdminHandler {
/**
* Constructs a StorageUsageHandler
instance.
*/
private StorageUsageHandler() {
users = Context.getAllUsers();
}
/**
* Returns the storage sizes of all users.
*
* @return the storage sizes
*/
public long[] getSizes() {
long sizes[] = new long[users.size()];
for(int i = 0; i < users.size(); i++) {
sizes[i] = getOneSize(users.get(i));
}
}
/**
* Returns the storage size of a user.
*
* @param user the specified user
* @return the storage size
*/
protected long getSize(User user) {
// do something...
return 0;
}
/**
* Displays the storage usage of users.
*
* @param req the http servlet request
* @param res the http servlet response
*
* @throws IOException
* @throws ServletException
*/
public void process(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
res.setContentType("text/html");
res.setHeader("Cache-Control", "no-cache");
res.setHeader("Pragma","no-cache");
res.setDateHeader("Expires", 0);
PrintWriter writer = new PrintWriter(res.getOutputStream());
long sizes[] = getsizes();
writer.println("
");
for(int i = 0; i < sizes.length; i++) {
writer.print("
");
}
"); writer.print(users.get(i) + ": " + sizes[i]); writer.println(" |
writer.println("");
writer.flush();
writer.close();
}
/**
* The users.
*/
private List users;
}
/**
* An admin servlet as a http servlet to process the admin http servlet
* request and response.
*
* @version 1.0 9/9/2003
* @author Bill
*/
public class AdminServlet extends HttpServlet {
/**
* Initiates the configuration.
*
* @param config the servlet config
*
* @throws ServletException
*/
private void initConfig(ServletConfig config) throws ServletException {
// do something...
handlerMap.put("__storage_Usage__", new StorageUsageHandler());
}
/**
* Processes the http servlet request and response.
*
* @throws IOException
* @throws ServletException
*/
public void service(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
AdminHandler handler = handlerMap.get(req.getParameter("handler"));
if(handler == null) {
// do something...
return;
}
handler.process(req, res);
}
/**
* The admin handler map(handler name->handler).
*/
private HashMap handlerMap = new HashMap();
}
您一定看出了問題所在吧!
Fragment 3中,由于StorageUsageHandler并不遵循Singleton模式,盡管StorageUsageHandler的類成員users只能在實例化StorageUsageHandler時被賦值,但是在單線程模式下,只要保證每次所使用的StorageUsageHandler實例是新實例化的,基本上還是沒有問題的。
問題在于,在初始化AdminServlet的過程中,StorageUsageHandler被實例化并存儲起來。此后,除非servlet container重新裝載AdminServlet,否則將無法重新實例化StorageUsageHandler,也將無法更新StorageUsageHandler的類成員users。這樣,在發生了增加、刪除或修改用戶的操作之后,users將成為臟數據。
如何避免類使用所帶來的臟數據問題呢?
i. 對于與類外部無依賴關系的類成員,不存在這種問題;
ii. 對于依賴于類外部的類成員,且該類成員不存在更新機制。最好是將其去掉,需要時從類外部直接獲取;如果這種辦法不可行,應提供機制以確保在使用該類成員之前,該類成員已經被更新過;如果這種辦法還不可行,請清晰地說明類的使用方式,以防止不當的類使用發生。
到此,相信大家對“Java程序的臟數據問題實例分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。