您好,登錄后才能下訂單哦!
本篇內(nèi)容主要講解“Java程序的臟數(shù)據(jù)問題實(shí)例分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“Java程序的臟數(shù)據(jù)問題實(shí)例分析”吧!
臟數(shù)據(jù)(Out-of-date data),指過時的數(shù)據(jù)。
如果在您的Java程序中存在臟數(shù)據(jù),將或多或少地給軟件系統(tǒng)帶來一些問題,如:無法實(shí)時地應(yīng)用已經(jīng)發(fā)生改變的配置,軟件系統(tǒng)出現(xiàn)一些莫名其妙的、難以重現(xiàn)的、后果嚴(yán)重的錯誤等等。盡量避免臟數(shù)據(jù)的存在是非常有價值的。本文希望能在這方面給同行們一點(diǎn)幫助。
Fragment 1. 緩存技術(shù)的臟數(shù)據(jù)問題
/**
* 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所對應(yīng)的report font開銷較大,使用了緩存技術(shù)來避免這種開銷。這是一種常見的提高性能的方式,而且在一般情況下運(yùn)行良好。但是Fragment 1的設(shè)計與實(shí)現(xiàn)可能是不完備的,因為極有可能一個java font所對應(yīng)的report font在系統(tǒng)啟動之后發(fā)生變化,在這種變化發(fā)生之后,只有重啟軟件系統(tǒng)才能裝載之,這常常是最終用戶的抱怨之一。更可怕的是,類似的這種臟數(shù)據(jù)的存在還可能帶來其它嚴(yán)重的、無法想象的后果。
如何避免使用緩存技術(shù)所帶來的臟數(shù)據(jù)問題呢?
在設(shè)計、實(shí)現(xiàn)和測試時,應(yīng)該清晰定義緩存數(shù)據(jù)的更新:
i. 不考慮緩存數(shù)據(jù)的更新,重啟軟件系統(tǒng)是一種必要的方式;
ii. 不考慮緩存數(shù)據(jù)的更新,緩存數(shù)據(jù)不可能成為臟數(shù)據(jù)(但在軟件系統(tǒng)中,往往“不可能”會在一次又一次的重構(gòu)之后變?yōu)椤翱赡堋?;
iii. 考慮緩存數(shù)據(jù)的更新,當(dāng)源數(shù)據(jù)變化時,實(shí)時更新緩存數(shù)據(jù)。
Fragment 2. Singleton模式的臟數(shù)據(jù)問題
/**
* 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中,由于沒有必要次次實(shí)例化StorageUsageHandler而帶來不必要的開銷,采用了Singleton模式以保證StorageUsageHandler只被實(shí)例化一次。
在實(shí)例化SotrageUsageHandler時,StorageUsageHandler的類成員users將被賦值。由于不存在任何對users重新賦值的方法,一直駐留在軟件系統(tǒng)中的users將不會發(fā)生任何變化。在軟件系統(tǒng)啟動之后,增加、刪除或修改用戶的操作經(jīng)常會發(fā)生,而一旦發(fā)生這類操作,users就成為了臟數(shù)據(jù),F(xiàn)ragment 2將無法正常工作。
如何避免使用Singleton模式所帶來的臟數(shù)據(jù)問題呢?
對于Singleton類的類成員:
i. 對于與Singleton類外部無依賴關(guān)系的類成員,不存在這種問題;
ii. 對于依賴于Singleton類外部的類成員,且該類成員不存在更新機(jī)制,最好是將其去掉,需要時從Singleton類外部直接獲??;如果這種辦法不可行,應(yīng)提供機(jī)制以確保在使用該類成員之前,該類成員已經(jīng)被更新過。
Fragment 3. 類使用的臟數(shù)據(jù)問題
/**
* 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只能在實(shí)例化StorageUsageHandler時被賦值,但是在單線程模式下,只要保證每次所使用的StorageUsageHandler實(shí)例是新實(shí)例化的,基本上還是沒有問題的。
問題在于,在初始化AdminServlet的過程中,StorageUsageHandler被實(shí)例化并存儲起來。此后,除非servlet container重新裝載AdminServlet,否則將無法重新實(shí)例化StorageUsageHandler,也將無法更新StorageUsageHandler的類成員users。這樣,在發(fā)生了增加、刪除或修改用戶的操作之后,users將成為臟數(shù)據(jù)。
如何避免類使用所帶來的臟數(shù)據(jù)問題呢?
i. 對于與類外部無依賴關(guān)系的類成員,不存在這種問題;
ii. 對于依賴于類外部的類成員,且該類成員不存在更新機(jī)制。最好是將其去掉,需要時從類外部直接獲??;如果這種辦法不可行,應(yīng)提供機(jī)制以確保在使用該類成員之前,該類成員已經(jīng)被更新過;如果這種辦法還不可行,請清晰地說明類的使用方式,以防止不當(dāng)?shù)念愂褂冒l(fā)生。
到此,相信大家對“Java程序的臟數(shù)據(jù)問題實(shí)例分析”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。