#
線程的同步是保證多線程安全訪問競爭資源的一種手段。
線程的同步是Java多線程編程的難點,往往開發(fā)者搞不清楚什么是競爭資源、什么時候需要考慮同步,怎么同步等等問題,當(dāng)然,這些問題沒有很明確的答案,但有些原則問題需要考慮,是否有競爭資源被同時改動的問題?
在本文之前,請參閱《Java線程:線程的同步與鎖》,本文是在此基礎(chǔ)上所寫的。
對于同步,在具體的Java代碼中需要完成一下兩個操作:
把競爭訪問的資源標(biāo)識為private;
同步哪些修改變量的代碼,使用synchronized關(guān)鍵字同步方法或代碼。
當(dāng)然這不是唯一控制并發(fā)安全的途徑。
synchronized關(guān)鍵字使用說明
synchronized只能標(biāo)記非抽象的方法,不能標(biāo)識成員變量。
為了演示同步方法的使用,構(gòu)建了一個信用卡賬戶,起初信用額為100w,然后模擬透支、存款等多個操作。顯然銀行賬戶User對象是個競爭資源,而多個并發(fā)操作的是賬戶方法oper(int x),當(dāng)然應(yīng)該在此方法上加上同步,并將賬戶的余額設(shè)為私有變量,禁止直接訪問。
/**
* Java線程:線程的同步
*
* @author leizhimin 2009-11-4 11:23:32
*/
public class Test {
public static void main(String[] args) {
User u = new User("張三", 100);
MyThread t1 = new MyThread("線程A", u, 20);
MyThread t2 = new MyThread("線程B", u, -60);
MyThread t3 = new MyThread("線程C", u, -80);
MyThread t4 = new MyThread("線程D", u, -30);
MyThread t5 = new MyThread("線程E", u, 32);
MyThread t6 = new MyThread("線程F", u, 21);
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
}
}
class MyThread extends Thread {
private User u;
private int y = 0;
MyThread(String name, User u, int y) {
super(name);
this.u = u;
this.y = y;
}
public void run() {
u.oper(y);
}
}
class User {
private String code;
private int cash;
User(String code, int cash) {
this.code = code;
this.cash = cash;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
/**
* 業(yè)務(wù)方法
* @param x 添加x萬元
*/
public synchronized void oper(int x) {
try {
Thread.sleep(10L);
this.cash += x;
System.out.println(Thread.currentThread().getName() + "運行結(jié)束,增加“" + x + "”,當(dāng)前用戶賬戶余額為:" + cash);
Thread.sleep(10L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "User{" +
"code='" + code + '\'' +
", cash=" + cash +
'}';
}
}
輸出結(jié)果:
線程A運行結(jié)束,增加“20”,當(dāng)前用戶賬戶余額為:120
線程F運行結(jié)束,增加“21”,當(dāng)前用戶賬戶余額為:141
線程E運行結(jié)束,增加“32”,當(dāng)前用戶賬戶余額為:173
線程C運行結(jié)束,增加“-80”,當(dāng)前用戶賬戶余額為:93
線程B運行結(jié)束,增加“-60”,當(dāng)前用戶賬戶余額為:33
線程D運行結(jié)束,增加“-30”,當(dāng)前用戶賬戶余額為:3
Process finished with exit code 0
反面教材,不同步的情況,也就是去掉oper(int x)方法的synchronized修飾符,然后運行程序,結(jié)果如下:
線程A運行結(jié)束,增加“20”,當(dāng)前用戶賬戶余額為:61
線程D運行結(jié)束,增加“-30”,當(dāng)前用戶賬戶余額為:63
線程B運行結(jié)束,增加“-60”,當(dāng)前用戶賬戶余額為:3
線程F運行結(jié)束,增加“21”,當(dāng)前用戶賬戶余額為:61
線程E運行結(jié)束,增加“32”,當(dāng)前用戶賬戶余額為:93
線程C運行結(jié)束,增加“-80”,當(dāng)前用戶賬戶余額為:61
Process finished with exit code 0
很顯然,上面的結(jié)果是錯誤的,導(dǎo)致錯誤的原因是多個線程并發(fā)訪問了競爭資源u,
tb并對u的屬性做了改動。
可見同步的重要性。
注意:
通過前文可知,線程退出同步方法時將釋放掉方法所屬對象的鎖,但還應(yīng)該注意的是,同步方法中還可以使用特定的方法對線程進(jìn)行調(diào)度。這些方法來自于java.lang.Object類。
void notify()
喚醒在此對象監(jiān)視器上等待的單個線程。
void notifyAll()
喚醒在此對象監(jiān)視器上等待的所有線程。
void wait()
導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對象的 notify() 方法或 notifyAll() 方法。
void wait(long timeout)
導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量。
void wait(long timeout, int nanos)
導(dǎo)致當(dāng)前的線程等待,直到其他線程調(diào)用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當(dāng)前線程,或者已超過某個實際時間量。
結(jié)合以上方法,處理多線程同步與互斥問題非常重要,著名的生產(chǎn)者-消費者例子就是一個經(jīng)典的例子,任何語言多線程必學(xué)的例子。
摘要: 本篇博文講兩件事情,一個是推薦在博客園經(jīng)常寫博客的童鞋們一個很棒的工具--“百度統(tǒng)計”,另一個是“拷貝百度統(tǒng)計”的頁面框架。
首先講第一個事情,我的博客里有不少文章都是講“用戶行為分析”的,雖然現(xiàn)在不做這個方向的項目,但是對它的興趣不減,所以我今天在自己博客里部署了百度的用戶行為分析系統(tǒng)“百度統(tǒng)計̶...
閱讀全文
對1.0版進(jìn)行了重構(gòu),去掉了一些花銷的功能,優(yōu)化了頁面樣式,現(xiàn)有功能:
1)、一次性把數(shù)據(jù)加載到頁面內(nèi)存,在頁面進(jìn)行分頁。
2)、使用jquery的ajax每次從服務(wù)器取數(shù)據(jù)分頁。
3)、支持自定義分頁條樣式,插件默認(rèn)實現(xiàn)兩種樣式可供選擇。
- <table id="table2" >
- <thead>
- <tr><th width="200px">網(wǎng)站名稱</th>
- <th width="100px">網(wǎng)址</th>
- <th width="100px">知名度</th>
- <th width="120px">訪問量</th>
- </tr>
- </thead>
- <tbody></tbody>
- </table>
-
- $("#table2").bigPage({ajaxData:{url:"ajax.php"}});
<table id="table2" >
<thead>
<tr><th width="200px">網(wǎng)站名稱</th>
<th width="100px">網(wǎng)址</th>
<th width="100px">tb知名度</th>
<th width="120px">訪問量</th>
</tr>
</thead>
<tbody></tbody>
</table>
$("#table2").bigPage({ajaxData:{url:"ajax.php"}});
更多的例子及代碼下載地址:
http://bigui4.sinaapp.com/index.html
摘要: 簡介
Spring提供的DAO(數(shù)據(jù)訪問對象)支持主要的目的是便于以標(biāo)準(zhǔn)的方式使用不同的數(shù)據(jù)訪問技術(shù),如JDBC,Hibernate或者JDO等。它不僅可以讓你方便地在這些持久化技術(shù)間切換, 而且讓你在編碼的時候不用考慮處理各種技術(shù)中特定的異常。
一致的異常層次
Spring提供了一種方便的方法,把特定于某種技術(shù)的異常,如SQLException, 轉(zhuǎn)化為自己的異常,這種異常屬于以 ...
閱讀全文
目前,最常用的三種動態(tài)網(wǎng)頁語言有ASP(Active Server Pages),JSP(JavaServer Pages),PHP (Hypertext Preprocessor)。
簡 介 :
ASP全名Active Server Pages,是一個WEB服務(wù)器端的開發(fā)環(huán)境,利用它可以產(chǎn)生和執(zhí)行動態(tài)的、互動的、高性能的WEB服務(wù)應(yīng)用程序
(1)ASP采用腳本語言VBScript(Java script)作為自己的開發(fā)語言。
(2)PHP是一種跨平臺的服務(wù)器端的嵌入式腳本語言。它大量地借用C, Java和Perl語言的語法, 并耦合PHP自己的特性,使WEB開發(fā)者能夠快速地寫出動態(tài)產(chǎn)生頁面。它支持目前絕大多數(shù)數(shù)據(jù)庫。還有一點,PHP是完全免費的,不用花錢,你可以從PHP官方站點(http: //www.php.net)自由下載。而且你可以不受限制地獲得源碼,甚至可以從中加進(jìn)你自己需要的特色。
(3)JSP是Sun公司推出的新一代網(wǎng)站開發(fā)語言,Sun公司借助自己在Java上的不凡造詣,將Java從Java應(yīng)用程序和Java Applet之外,又有新的碩果,就是JSP,Java Server Page。JSP可以在Serverlet和JavaBean的支持下,完成功能強大的站點程序。
三者都提供在 HTML代碼中混合某種程序代碼、由語言引擎解釋執(zhí)行程序代碼的能力。但JSP代碼被編譯成 Servlet并由Java虛擬機(jī)解釋執(zhí)行,這種編譯操作僅在對JSP頁面的第一次請求時發(fā)生。在ASP 、PHP、JSP環(huán)境下,HTML代碼主要負(fù)責(zé)描述信息的顯示樣式,而程序代碼則用來描述處理邏輯。普通的 HTML頁面只依賴于Web服務(wù)器,而ASP 、PHP、JSP頁面需要附加的語言引擎分析和執(zhí)行程序代碼。程序代碼的執(zhí)行結(jié)果被重新嵌入到HTML代碼中,然后一起發(fā)送給瀏覽器。ASP 、PHP、JSP三者都是面向Web服務(wù)器的技術(shù),客戶端瀏覽器不需要任何附加的軟件支持。
技術(shù)特點
ASP:
1. 使用VBScript 、 JScript等簡單易懂的腳本語言,結(jié)合HTML代碼,即可快速地完成網(wǎng)站的應(yīng)用程序。
2. 無須compile編譯,容易編寫,可在服務(wù)器端直接執(zhí)行。
3. 使用普通的文本編輯器,如Windows的記事本,即可進(jìn)行編輯設(shè)計。
4. 與瀏覽器無關(guān)(Browser Independence), 客戶端只要使用可執(zhí)行HTML碼的瀏覽器,即可瀏覽Actbive Server Pages所設(shè)計的網(wǎng)頁內(nèi)容。Active ServerPages 所使用的腳本語言(VBScript 、 Jscript)均在WEB服務(wù)器端執(zhí)行,客戶端的瀏覽器不需要能夠執(zhí)行這些腳本語言。
5.Active Server Pages能與任何ActiveX scripting語言兼容。除了可使用VB Script或JScript語言來設(shè)計外,還通過plug-in的方式,使用由第三方所提供的其它腳本語言,譬如REXX 、Perl 、Tcl等。腳本引擎是處理腳本程序的COM(Component Object Model) 對象。
6. 可使用服務(wù)器端的腳本來產(chǎn)生客戶端的腳本。
7. ActiveX Server Components(ActiveX 服務(wù)器組件 )具有無限可擴(kuò)充性。可以使用Visual Basic 、Java 、Visual C++ 、COBOL等程序設(shè)計語言來編寫你所需要的ActiveX Server Component 。
PHP:
1. 數(shù)據(jù)庫連接
PHP可以編譯成具有與許多數(shù)據(jù)庫相連接的函數(shù)。PHP與MySQL是現(xiàn)在絕佳的群組合。你還可以自己編寫外圍的函數(shù)去間接存取數(shù)據(jù)庫。通過這樣的途徑當(dāng)你更換使用的數(shù)據(jù)庫時,可以輕松地修改編碼以適應(yīng)這樣的變化。PHPLIB就是最常用的可以提供一般事務(wù)需要的一系列基庫。但PHP提供的數(shù)據(jù)庫接口支持彼此不統(tǒng)一,比如對Oracle, MySQL,Sybase的接口,彼此都不一樣。這也是PHP的一個弱點。
JSP:
1. 將內(nèi)容的產(chǎn)生和顯示進(jìn)行分離
使用JSP技術(shù),Web頁面開發(fā)人員可以使用HTML或者XML標(biāo)識來設(shè)計和格式化最終頁面。使用JSP標(biāo)識或者小腳本來產(chǎn)生頁面上的動態(tài)內(nèi)容。產(chǎn)生內(nèi)容的邏輯被封裝在標(biāo)識和JavaBeans群組件中,并且捆綁在小腳本中,所有的腳本在服務(wù)器端執(zhí)行。如果核心邏輯被封裝在標(biāo)識和Beans中,那么其它人,如Web管理人員和頁面設(shè)計者,能夠編輯和使用JSP頁面,而不影響內(nèi)容的產(chǎn)生。在服務(wù)器端,JSP引擎解釋JSP標(biāo)識,產(chǎn)生所請求的內(nèi)容(例如,通過存取JavaBeans群組件,使用JDBC技術(shù)存取數(shù)據(jù)庫),并且將結(jié)果以HTML(或者XML)頁面的形式發(fā)送回瀏覽器。這有助于作者保護(hù)自己的代碼,而又保證任何基于HTML的Web瀏覽器的完全可用性。
2. 強調(diào)可重用的群組件
絕大多數(shù)JSP頁面依賴于可重用且跨平臺的組件(如:JavaBeans或者Enterprise JavaBeans)來執(zhí)行應(yīng)用程序所要求的更為復(fù)雜的處理。開發(fā)人員能夠共享和交換執(zhí)行普通操作的組件,或者使得這些組件為更多的使用者或者用戶團(tuán)體所使用。基于組件的方法加速了總體開發(fā)過程,并且使得各種群組織在他們現(xiàn)有的技能和優(yōu)化結(jié)果的開發(fā)努力中得到平衡。
3. 采用標(biāo)識簡化頁面開發(fā)
Web頁面開發(fā)人員不會都是熟悉腳本語言的程序設(shè)計人員。JavaServer Page技術(shù)封裝了許多功能,這些功能是在易用的、與JSP相關(guān)的XML標(biāo)識中進(jìn)行動態(tài)內(nèi)容產(chǎn)生所需要的。標(biāo)準(zhǔn)的JSP標(biāo)識能夠存取和實例化 JavaBeans組件,設(shè)定或者檢索群組件屬性,下載Applet,以及執(zhí)行用其它方法更難于編碼和耗時的功能。
通過開發(fā)定制化標(biāo)識庫,JSP技術(shù)是可以擴(kuò)展的。今后,第三方開發(fā)人員和其它人員可以為常用功能建立自己的標(biāo)識庫。這使得Web頁面開發(fā)人員能夠使用熟悉的工具和如同標(biāo)識一樣的執(zhí)行特定功能的構(gòu)件來工作。
JSP技術(shù)很容易整合到多種應(yīng)用體系結(jié)構(gòu)中,以利用現(xiàn)存的工具和技巧,并且擴(kuò)展到能夠支持企業(yè)級的分布式應(yīng)用。作為采用Java技術(shù)家族的一部分,以及Java 2EE的一個成員,JSP技術(shù)能夠支持高度復(fù)雜的基于Web的應(yīng)用。
由于JSP頁面的內(nèi)置腳本語言是基于Java程序設(shè)計語言的,而且所有的JSP頁面都被編譯成為Java Servlet,JSP頁面就具有Java技術(shù)的所有好處,包括健壯的存儲管理和安全性。
作為Java平臺的一部分,JSP擁有Java程序設(shè)計語言“一次編寫,各處執(zhí)行”的特點。隨著越來越多的供貨商將JSP支持加入到他們的產(chǎn)品中,您可以使用自己所選擇的服務(wù)器和工具,修改工具或服務(wù)器并不影響目前的應(yīng)用。
應(yīng)用范圍
ASP是Microsoft開發(fā)的動態(tài)網(wǎng)頁語言,也繼承了微軟產(chǎn)品的一貫傳統(tǒng),只能執(zhí)行于微軟的服務(wù)器產(chǎn)品,IIS(Internet Information Server)(windows NT)和PWS(Personal Web Server)(windows 98)上。Unix下也有ChiliSoft的組件來支持ASP,但是ASP本身的功能有限,必須通過ASP+COM的群組合來擴(kuò)充,Unix下的COM實現(xiàn)起來非常困難。
PHP3可在Windows,Unix,Linux的Web服務(wù)器上正常執(zhí)行,還支持IIS,Apache等一般的Web服務(wù)器,用戶更換平臺時,無需變換PHP3代碼,可即拿即用。
JSP同PHP3類似,幾乎可以執(zhí)行于所有平臺。如Win NT,Linux,Unix。在NT下IIS通過一個外加服務(wù)器,例如JRUN或者ServletExec,就能支持JSP。知名的Web服務(wù)器Apache已經(jīng)能夠支持JSP。由于Apache廣泛應(yīng)用在NT、Unix和Linux上,因此JSP有更廣泛的執(zhí)行平臺。雖然現(xiàn)在NT操作系統(tǒng)占了很大的市場份額,但是在服務(wù)器方面Unix的優(yōu)勢仍然很大,而新崛起的Linux更是來勢不小。從一個平臺移植到另外一個平臺,JSP和JavaBean甚至不用重新編譯,因為Java字節(jié)碼都是標(biāo)準(zhǔn)的與平臺無關(guān)的。
性能比較
有人做過試驗,對這三種語言分別做回圈性能測試及存取Oracle數(shù)據(jù)庫測試。
在循環(huán)性能測試中,JSP只用了令人吃驚的四秒鐘就結(jié)束了20000*20000的回圈。而ASP、PHP測試的是2000*2000循環(huán)(少一個數(shù)量級),卻分別用了63秒和84秒。(參考PHPLIB)。
數(shù)據(jù)庫測試中,三者分別對 Oracle 8 進(jìn)行 1000 次 Insert,Update,Select和Delete: JSP 需要 13 秒,PHP 需要 69 秒,ASP則 需要73 秒。
前景分析
目前在國內(nèi)PHP與ASP應(yīng)用最為廣泛。而JSP由于是一種較新的技術(shù),國內(nèi)采用的較少。但在國外,JSP已經(jīng)是比較流行的一種技術(shù),尤其是電子商務(wù)類的網(wǎng)站,多采用JSP。
采用PHP的網(wǎng)站如新浪網(wǎng)(sina)、中國人(Chinaren)等,但由于PHP本身存在的一些缺點,使得它不適合應(yīng)用于大型電子商務(wù)站點,而更適合一些小型的商業(yè)站點。首先,PHP缺乏規(guī)模支持。其次,缺乏多層結(jié)構(gòu)支持。對于大負(fù)荷站點,解決方法只有一個:分布計算。數(shù)據(jù)庫、應(yīng)用邏輯層、表示邏輯層彼此分開,而且同層也可以根據(jù)流量分開,群組成二維數(shù)組。而PHP則缺乏這種支持。還有上面提到過的一點,PHP提供的數(shù)據(jù)庫接口支持不統(tǒng)一,這就使得它不適合運用在電子商務(wù)中。
ASP和JSP則沒有以上缺陷,ASP可以通過Microsoft Windowsd的COM/DCOM獲得ActiveX規(guī)模支持,通過DCOM和Transcation Server獲得結(jié)構(gòu)支持;JSP可以通過SUN Java的Java Class和EJB獲得規(guī)模支持,通過EJB/CORBA以及眾多廠商的Application Server獲得結(jié)構(gòu)支持。
三者中,JSP應(yīng)該是未來發(fā)展的趨勢。世界上一些大的電子商務(wù)解決方案提供商都采用JSP/Servlet。比較出名的如IBM的E-business,它的核心是采用JSP/Servlet的Web Sphere。它們都是通過CGI來提供支持的。但去年10月后它推出了Enfinity,一個采用JSP/Servlet的電子商務(wù)Application Server,而且聲言不再開發(fā)傳統(tǒng)軟件。
總之,ASP,PHP,JSP三者都有相當(dāng)數(shù)量的支持者,由此也可以看出三者各有所長。正在學(xué)習(xí)或使用動態(tài)頁面的朋友可根據(jù)三者的特點選擇一種適合自己的語言。
1、數(shù)據(jù)庫當(dāng)中的表設(shè)計

2、對應(yīng)數(shù)據(jù)表的實體Bean (id為主鍵)
- public class EnginConfigVO {
- int id = 0;
- int THREADS_COUNT;
-
-
-
-
- public int primaryGetId() {
- return id;
- }
-
-
-
- public void primarySetId(int id) {
- this.id = id;
- }
-
-
-
- public int getTHREADS_COUNT() {
- return THREADS_COUNT;
- }
-
-
-
-
- public void setTHREADS_COUNT(int tHREADS_COUNT) {
- THREADS_COUNT = tHREADS_COUNT;
- }
- }
public class EnginConfigVO {
int id = 0;
int THREADS_COUNT;
/**
* @return the id
*/
public int primaryGetId() {
return id;
}
/**
* @param id the id to set
*/
public void primarySetId(int id) {
this.id = id;
}
/**
* @return the tHREADS_COUNT
*/
public int getTHREADS_COUNT() {
return THREADS_COUNT;
}
/**
* @param tHREADS_COUNT the tHREADS_COUNT to set
*/
public void setTHREADS_COUNT(int tHREADS_COUNT) {
THREADS_COUNT = tHREADS_COUNT;
}
}
由于沒有像hibernate那樣的注解機(jī)制,所以只能在主鍵的setter和getter方法上動動手腳primaryGetId() ,primarySetId(int id)
而實體bean的類名在與數(shù)據(jù)表的匹配上最后多了“vo” 兩個字母,所以在tb下面方法中將這兩個字母剪裁掉。
反射方法:
T o 對應(yīng)的就是實體Bean,這樣的方法當(dāng)然是寫在DAO層中,供上層的service調(diào)用,傳入需要修改的實體Bean
- public <T> void updatePropertiesValues(T o) {
- StringBuilder sd = new StringBuilder("update ");
- sd.append(o.getClass().getSimpleName().toLowerCase().substring(0, o.getClass().getSimpleName().length()-2)).append(" ");
- sd.append("set ");
- StringBuilder id = new StringBuilder("where ");
- try {
- for(Method m : o.getClass().getDeclaredMethods()) {
- String name = m.getName();
- if (name.startsWith("get")) {
- sd.append(name.substring(3).toLowerCase()).append("=");
- if(m.invoke(o) instanceof String) {
- sd.append("'").append(m.invoke(o)).append("', ");
- }else {
- sd.append(m.invoke(o)).append(", ");
- }
- }
- if(name.startsWith("primaryGet")) {
- id.append(name.substring(10).toLowerCase()).append("=");
- if(m.invoke(o) instanceof String) {
- id.append("'").append(m.invoke(o)).append("';");
- }else {
- id.append(m.invoke(o)).append(";");
- }
- }
- }
- sd.delete(sd.length()-2, sd.length());
- sd.append(" ");
- sd.append(id);
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
-
- executeTrans(sd.toString());
-
- }
public <T> void updatePropertiesValues(T o) {
StringBuilder sd = new StringBuilder("update ");
sd.append(o.getClass().getSimpleName().toLowerCase().substring(0, o.getClass().getSimpleName().length()-2)).append(" ");
sd.append("set ");
StringBuilder id = new StringBuilder("where ");
try {
for(Method m : o.getClass().getDeclaredMethods()) {
String name = m.getName();
if (name.startsWith("get")) {
sd.append(name.substring(3).toLowerCase()).append("=");
if(m.invoke(o) instanceof String) {
sd.append("'").append(m.invoke(o)).append("', ");
}else {
sd.append(m.invoke(o)).append(", ");
}
}
if(name.startsWith("primaryGet")) {
id.append(name.substring(10).toLowerCase()).append("=");
if(m.invoke(o) instanceof String) {
id.append("'").append(m.invoke(o)).append("';");
}else {
id.append(m.invoke(o)).append(";");
}
}
}
sd.delete(sd.length()-2, sd.length());
sd.append(" ");
sd.append(id);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
executeTrans(sd.toString());
}
這樣以后便可以拼湊出完整的sql語句,為我們解決了功能相似代碼的冗余。。
另外在查找時,我們還可以利用發(fā)射機(jī)制,將數(shù)據(jù)庫返回的resultset 對象包裝成List<T>
- public static <T> List<T> getObjectsList(ResultSet rs, Class<T> k)
- throws SQLException {
- List<T> bl = new ArrayList<T>();
- if (rs != null) {
- while (rs.next()) {
-
- T o = null;
- try {
- o = k.newInstance();
- for (Method m : k.getDeclaredMethods()) {
- String name = m.getName();
- if (name.startsWith("set")) {
-
- m.invoke(o, rs.getObject(name.substring(3)));
- }
- }
- bl.add(o);
- } catch (InstantiationException e) {
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- e.printStackTrace();
- }
- }
- return bl;
- }
- return null;
- }
public static <T> List<T> getObjectsList(ResultSet rs, Class<T> k)
throws SQLException {
List<T> bl = new ArrayList<T>();
if (rs != null) {
while (rs.next()) {
// System.out.println("result is not null");
T o = null;
try {
o = k.newInstance();
for (Method m : k.getDeclaredMethods()) {
String name = m.getName();
if (name.startsWith("set")) {
// System.out.println(rs.getObject(name.substring(3)).getClass().getName());
m.invoke(o, rs.getObject(name.substring(3)));
}
}
bl.add(o);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return bl;
}
return null;
}
這樣,我們就可以從底層直接獲得包裝好的List<T>集合。。不足之處,歡迎大家討論。。
java 單例加鎖方法:
ScheduleEngine是個單例類,在獲得實例的方法getinstance中,兩次判斷其是否為空,有利于多線程的并發(fā)操作。
使得實例化時,只在第一次加鎖,這樣效率會有提高。
- class ScheduleEngine{
-
- private static Lock instanceLock=new ReentrantLock();
-
- private ScheduleEngine() {
- setproperties;
- }
-
- public static ScheduleEngine getInstance(int temphandlerType) {
- if(null==engine) {
- instanceLock.lock();
- try
- {
- if(null==engine)
- {
- handlerType=temphandlerType;
- engine=new ScheduleEngine(temphandlerType);
- }
-
- }
- finally
- {
- instanceLock.unlock();
- }
- }
- return engine;
- }
- }
class ScheduleEngine{
private static Lock instanceLock=new ReentrantLock();
private ScheduleEngine() {
setproperties;
}
public static ScheduleEngine getInstance(int temphandlerType) {
if(null==engine) {
instanceLock.lock();
try
{
if(null==engine)
{
handlerType=temphandlerType;
engine=new ScheduleEngine(temphandlerType);
}
}
finally
{
instanceLock.unlock();
}
}
return engine;
}
}
初始實例化 單例c3p0對象的方法,常用的是
public final class ConnectionManager {
private static ConnectionManager instance;
private static ComboPooledDataSource cpds;
private static String c3p0Properties;
/**
* 從數(shù)據(jù)庫連接池取連接
* @throws Exception
*/
private ConnectionManager() throws Exception {
Properties p = new Properties();
c3p0Properties = System.getProperty("user.dir") +
"/mom_project_config/database.properties";
// p.load(this.getClass().getClassLoader().getResourceAsStream(c3p0Properties));
p.load(new BufferedInputStream(new FileInputStream(c3p0Properties)));
// String url = p.getProperty("url") + p.getProperty("database");
String url = p.getProperty("url") + p.getProperty("database")+"?useUnicode=true&characterEncoding=UTF-8";
cpds = new ComboPooledDataSource();
cpds.setDriverClass(p.getProperty("driverclass"));
cpds.setJdbcUrl(url);
cpds.setUser(p.getProperty("user"));
cpds.setPassword(p.getProperty("password"));
// 當(dāng)連接池中的連接耗盡的時候c3p0一次同時獲取的連接數(shù)。Default: 3 acquireIncrement
cpds.setAcquireIncrement(Integer.valueOf(p
.getProperty("acquireincrement")));
// 定義在從數(shù)據(jù)庫獲取新連接失敗后重復(fù)嘗試的次數(shù)。Default: 30 acquireRetryAttempts
cpds.setAcquireRetryAttempts(Integer.valueOf(p
.getProperty("acquireretryattempts")));
// 兩次連接中間隔時間,tb單位毫秒。Default: 1000 acquireRetryDelay
cpds.setAcquireRetryDelay(Integer.valueOf(p
.getProperty("acquireretrydelay")));
// 自動提交事務(wù);連接關(guān)閉時默認(rèn)將所有未提交的操作回滾。Default: false autoCommitOnClose
cpds.setAutoCommitOnClose(Boolean.valueOf(p
.getProperty("autocommitonclose")));
// 當(dāng)連接池用完時客戶端調(diào)用getConnection()后等待獲取新連接的時間,超時后將拋出SQLException,
// 如設(shè)為0則無限期等待.單位毫秒,默認(rèn)為0
cpds.setCheckoutTimeout(Integer.valueOf(p
.getProperty("checkouttimeout")));
// 每多少秒檢查所有連接池中的空閑連接。默認(rèn)為0表示不檢查。Default: 0 idleConnectionTestPeriod
cpds.setIdleConnectionTestPeriod(Integer.valueOf(p
.getProperty("idleconnectiontestperiod")));
// 最大空閑時間,25000秒內(nèi)未使用則連接被丟棄。若為0則永不丟棄。Default: 0 maxIdleTime
cpds.setMaxIdleTime(Integer.valueOf(p.getProperty("maxidletime")));
// 初始化時獲取三個連接,取值應(yīng)在minPoolSize與maxPoolSize之間。Default: 3 initialPoolSize
cpds.setInitialPoolSize(Integer.valueOf(p
.getProperty("initialpoolsize")));
// 連接池中保留的最小連接數(shù)。
cpds.setMinPoolSize(Integer.valueOf(p.getProperty("minpoolsize")));
// 連接池中保留的最大連接數(shù)。Default: 15 maxPoolSize
cpds.setMaxPoolSize(Integer.valueOf(p.getProperty("maxpoolsize")));
// JDBC的標(biāo)準(zhǔn)參數(shù),用以控制數(shù)據(jù)源內(nèi)加載的PreparedStatement數(shù)據(jù).但由于預(yù)緩存的Statement屬于單個Connection而不是整個連接池.所以
// 設(shè)置這個參數(shù)需要考濾到多方面的因素,如果maxStatements與maxStatementsPerConnection均為0,則緩存被關(guān)閉.默認(rèn)為0;
cpds.setMaxStatements(Integer.valueOf(p.getProperty("maxstatements")));
// 連接池內(nèi)單個連接所擁有的最大緩存被關(guān)閉.默認(rèn)為0;
cpds.setMaxStatementsPerConnection(Integer.valueOf(p
.getProperty("maxstatementsperconnection")));
// C3P0是異步操作的,緩慢的JDBC操作通過幫助進(jìn)程完成.擴(kuò)展這些操作可以有效的提升性能,通過多數(shù)程實現(xiàn)多個操作同時被執(zhí)行.默為為3
cpds.setNumHelperThreads(Integer.valueOf(p
.getProperty("numhelperthreads")));
// 用戶修改系統(tǒng)配置參數(shù)執(zhí)行前最多等待的秒數(shù).默認(rèn)為300;
cpds.setPropertyCycle(Integer.valueOf(p.getProperty("propertycycle")));
// 如果設(shè)為true那么在取得連接的同時將校驗連接的有效性。Default: false testConnectionOnCheckin
cpds.setTestConnectionOnCheckin(Boolean.valueOf(p
.getProperty("testconnectiononcheckin")));
// 因性能消耗大請只在需要的時候使用它。
// 如果設(shè)為true那么在每個connection提交的時候都將校驗其有效性。
// 建議使用idleConnectionTestPeriod或automaticTestTable等方法來提升連接測試的性能。Default:
// false testConnectionOnCheckout
cpds.setTestConnectionOnCheckout(Boolean.valueOf(p
.getProperty("testconnectionOncheckout")));
// 獲取連接失敗將會引起所有等待連接池來獲取連接的線程拋出異常。
// 但是數(shù)據(jù)源仍有效保留,并在下次調(diào)用getConnection()的時候繼續(xù)嘗試獲取連接。
// 如果設(shè)為true,那么在嘗試獲取連接失敗后該數(shù)據(jù)源將申明已斷開并永久關(guān)閉。Default: false
// breakAfterAcquireFailure
cpds.setBreakAfterAcquireFailure(Boolean.valueOf(p
.getProperty("breakafteracquirefailure")));
}
/**
* 獲得ConnectionManager單例對象
* @return
*/
public synchronized static ConnectionManager getInstance() {
if (instance == null) {
try {
instance = new ConnectionManager();
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
/**
* 獲得連接
* @return
*/
public Connection getContection() {
try {
return cpds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
在初始化獲得單例的方法上面加鎖,不利于并發(fā)操作的執(zhí)行,用第一段代碼兩次判斷是否為空的方式,可以減少代碼執(zhí)行中鎖的引用。 不足之處煩請朋友們指正。。
Java在網(wǎng)絡(luò)編程這個地方做的很好,java的主要目的也是為了網(wǎng)絡(luò)而生的,它能方便的訪問網(wǎng)絡(luò)上的資源。我們這節(jié)課來介紹網(wǎng)絡(luò)通訊的兩種機(jī)制:URL通信機(jī)制,Socket通信機(jī)制。
URL表示了Internet上一個資源的引用或地址。Java網(wǎng)絡(luò)應(yīng)用程序也是使用URL來定位要訪問的Internet的資源。在jdk里面java.net.URL也是一個類,它來封裝URL的一些細(xì)節(jié)。目前大家可以把URL理解為網(wǎng)址,default.aspx 這就是個URL.http是協(xié)議名(超文本傳輸協(xié)議)用“://”隔開www.tbwshc.com 是主機(jī)名。Default.aspx是文件名。它的端口號沒有寫,默認(rèn)是80.
實踐:
import java.net.*;
public class ParseURL {
public static void main(String[] args) throws MalformedURLException{
URL url = new URL("http://www.100jq.com:45175/default.aspx");
System.out.println("協(xié)議是 "+url.getProtocol());
System.out.println("主機(jī)是 "+url.getHost());
System.out.println("文件名是 "+url.getFile());
System.out.println("端口號是 "+url.getPort());
}}
/*
URL這個對象中提供了很多方法像是
getProtocol()
getHost()
getFile()
getPort()
*/ |
我們可以通過URL對文件或資源讀取,tb也可以通過URLConnection讀取,也可以通過這個寫入數(shù)據(jù)限于cgi腳本。
實踐:
import java.net.*;
import java.io.*;
public class URLConnectionReader {
public static void main(String[] args) throws IOException {
URL google = new URL("");
URLConnection g = google.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(g.getInputStream()));
String inputLine;
while ((inputLine=in.readLine())!=null)
System.out.println(inputLine);
in.close();
}} |
URL和URLConnection類提供了較高層次的網(wǎng)絡(luò)訪問。有時候需要進(jìn)行較低層次的訪問。編寫C/S模型的程序時,就要使用Socket通信機(jī)制了。因為在網(wǎng)絡(luò)上不一定非得訪問文件。
實踐:
//先寫個客戶端的應(yīng)用
import java.net.*;
import java.io.*;
public class SimpleClient {
public static void main(String args[]) {
try {
// 在5432端口打開服務(wù)器連接
// 在這里用localhost與127.0.0.1是一個意思
Socket s1 = new Socket("127.0.0.1", 5432);
// 對這個端口連接一個reader,注意端口不能夠占用別的
BufferedReader br = new BufferedReader(
new InputStreamReader(s1.getInputStream()));
// 讀取輸入的數(shù)據(jù)并且打印在屏幕上
System.out.println(br.readLine());
//當(dāng)完成時關(guān)閉流和連接
br.close();
s1.close();
} catch (ConnectException connExc) {
System.err.println("Could not connect to the server.");
} catch (IOException e) {
// ignore
}}}
//這是服務(wù)端的應(yīng)用
import java.net.*;
import java.io.*;
public class SimpleServer {
public static void main(String args[]) {
ServerSocket s = null;
// 注冊服務(wù)端口為5432
try {
s = new ServerSocket(5432);
} catch (IOException e) {
e.printStackTrace();
}
// 運行監(jiān)聽器并接收,永遠(yuǎn)循環(huán)下去。因為服務(wù)器總要開啟的
while (true) {
try {
// 等待一個連接的請求
Socket s1 = s.accept();
// 得到端口的輸出流
OutputStream s1out = s1.getOutputStream();
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(s1out));
// 發(fā)送一個字符串
bw.write("百家拳軟件項目研究室歡迎您!\n");
// 關(guān)閉這個連接, 但不是服務(wù)端的socket
bw.close();
s1.close();
} catch (IOException e) {
e.printStackTrace();
}}}} |
下載 target=_blank>上述例子打包下載
執(zhí)行這個程序和其它的不太一樣,先用javac將兩個文件編譯之后。然后敲start開啟另一個窗口。用start命令開啟的窗口繼承了原來窗口的特性。如圖26-1所示

圖26-1
接著在原來的窗口上執(zhí)行服務(wù)端程序java SimpleServer.在新窗口中執(zhí)行java SimpleClient 就會看到結(jié)果了。注意如果如果在啟動服務(wù)端的時候拋出bindException則說明5432這個端口已經(jīng)被別的程序占用著,改成別的端口號就可以了。通常選用端口的時候,其數(shù)字最好不要小于1024,1024一下的端口很多都是專用的端口。
現(xiàn)在的java界,很多東西叫××let,××let的意思都是些小程序的意思。例如:applet應(yīng)用程序的小程序,servlet服務(wù)器端的小程序,midlet手機(jī)中的小程序,portlet門戶容器端的小程序。這節(jié)我們介紹applet.這個東西用的不是很多,但是在java的體系結(jié)構(gòu)中是很有意義的。這個東西是能夠在瀏覽器里運行的,可以潛入到HTML頁面里。我們知道普通的Application要有main()作為入口點運行,而Applet要在瀏覽器里運行,或者開發(fā)時查看的時候用appletviewer運行。舉個例子,實踐:
import java.awt.*;
import java.applet.*;
@SuppressWarnings("serial") //抑制警告
//所有的Applet,都繼承了java.applet.Applet
public class HelloApplet extends Applet {
public void paint(Graphics g){
g.drawString("百家拳軟件項目研究室!",30,30);
}} |
還需要建立一個html文件,因為剛才說了它可以嵌入在瀏覽器里面。用記事本建立一個hello.html代碼如下:
<applet code="HelloApplet.class" width=150 heightb=150></applet>
之后照樣用javac編譯剛才那個類。最后在命令行中輸入appletviewer hello.html可以看到結(jié)果。
這種小程序彌補了B/S模型的不足,用瀏覽器可以執(zhí)行客戶端的東西。因為它功能強大,所以是個不錯的東西。可是功能太強大了,又引發(fā)了一些安全性的問題。所以瀏覽器也會對applet做了一些安全性的限制。Applet還有一種叫做沙箱模型的機(jī)制,它使得沒有訪問權(quán)限的資源,不能訪問。保證了安全性。同時開發(fā)時也不是那么方便。Applet又跨平臺的特性。
而且微軟的IE瀏覽器里面在運行applet的時候速度不是很快,不如activex的方便。界面也不是太漂亮。不過它的這種在瀏覽器中運行的思想還是比較不錯的。
1 、對象的初始化
(1 )非靜態(tài)對象的初始化
在創(chuàng)建對象時,對象所在類的所有數(shù)據(jù)成員會首先進(jìn)行初始化。
基本類型:int 型,初始化為0.
如果為對象:這些對象會按順序初始化。
※在所有類成員初始化完成之后,才調(diào)用本類的構(gòu)造方法創(chuàng)建對象。
構(gòu)造方法的作用就是初始化。
(2 )靜態(tài)對象的初始化
程序中主類的靜態(tài)變量會在main方法執(zhí)行前初始化。
不僅第一次創(chuàng)建對象時,類中的所有靜態(tài)變量都初始化,并且第一次訪問某
類(注意此時未創(chuàng)建此類對象)的靜態(tài)對象時,所有的靜態(tài)變量也要按它們在類
中的順序初始化。
2 、繼承時,對象的初始化過程
(1 )主類的超類由高到低按順序初始化靜態(tài)成員,無論靜態(tài)成員是否為private.
(2 )主類靜態(tài)成員的初始化。
(3 )主類的超類由高到低進(jìn)行默認(rèn)構(gòu)造方法的調(diào)用。注意,在調(diào)用每一個
超類的默認(rèn)構(gòu)造方法前,先進(jìn)行對此超類進(jìn)行非靜態(tài)對象的初始化。
(4 )主類非靜態(tài)成員的初始化。
(5 )調(diào)用主類的構(gòu)造方法。
3 、關(guān)于構(gòu)造方法
(1 )類可以沒有構(gòu)造方法,但如果有多個構(gòu)造方法,就應(yīng)該要有默認(rèn)的構(gòu)
造方法,否則在繼承此類時,需要在子類中顯式調(diào)用父類的某一個非默認(rèn)的構(gòu)造
方法了。
(2 )在一個構(gòu)造方法中,只能調(diào)用一次其他的構(gòu)造方法,并且調(diào)用構(gòu)造方
法的語句必須是第一條語句。
4 、有關(guān)public、private 和protected
(1 )無public修飾的類,可以被其他類訪問的條件是:a.兩個類在同一文
件中,b.兩個類在同一文件夾中,c.兩個類在同一軟件包中。
(2 )protected :繼承類和同一軟件包的類可訪問。
(3 )如果構(gòu)造方法為private ,那么在其他類中不能創(chuàng)建該類的對象。
5 、抽象類
(1 )抽象類不能創(chuàng)建對象。
(2 )如果一個類中一個方法為抽象方法,則這個類必須為abstract抽象類。
(3 )繼承抽象類的類在類中必須實現(xiàn)抽象類中的抽象方法。
(4 )抽象類中可以有抽象方法,也可有非抽象方法。抽象方法不能為private.
(5 )間接繼承抽象類的類可以不給出抽象方法的定義。
6 、final 關(guān)鍵字
(1 )一個對象是常量,不代表不能轉(zhuǎn)變對象的成員,仍可以其成員進(jìn)行操
作。
(2 )常量在使用前必須賦值,但除了在聲明的同時初始化外,就只能在構(gòu)
造方法中初始化。
(3 )final 修飾的方法不能被重置(在子類中不能出現(xiàn)同名方法)。
(4 )如果聲明一個類為final ,則所有的方法均為final ,無論其是否被
final 修飾,但數(shù)據(jù)成員可為final 也可不是。
7 、接口interface (用implements來實現(xiàn)接口)
(1 )接口中的所有數(shù)據(jù)均為static和final 即靜態(tài)常量。盡管可以不用這
兩個關(guān)鍵字修飾,但必須給常量賦初值。
(2 )接口中的方法均為public,在實現(xiàn)接口類中,實現(xiàn)方法必須可public
關(guān)鍵字。
(3 )如果使用public來修飾接口,則接口必須與文件名相同。
8 、多重繼承
(1 )一個類繼承了一個類和接口,那么必須將類寫在前面,接口寫在后面,
接口之間用逗號分隔。
(2 )接口之間可多重繼承,注意使用關(guān)鍵字extends.
(3 )一個類雖只實現(xiàn)了一個接口,但不僅要實現(xiàn)這個接口的所有方法,還
要實現(xiàn)這個接口繼承的接口的方法,接口中的所有方法均須在類中實現(xiàn)。
9 、接口的嵌入
(1 )接口嵌入類中,可以使用private 修飾。此時,接口只能在所在的類
中實現(xiàn),其他類不能訪問。
(2 )嵌入接口中的接口一定要為public.
10、類的嵌入
(1 )類可以嵌入另一個類中,但不能嵌入接口中。
(2 )在靜態(tài)方法或其他方法中,不能直接創(chuàng)建內(nèi)部類tb對象,需通過手段來
取得。
手段有兩種:
class A { class B {} B getB () { B b = new B(); return b ; }
} static void m () { A a = new A(); A.B ab = a.getB(); // 或者
是 A.B ab = a.new B (); }
(3 )一個類繼承了另一個類的內(nèi)部類,因為超類是內(nèi)部類,而內(nèi)部類的構(gòu)
造方法不能自動被調(diào)用,這樣就需要在子類的構(gòu)造方法中明確的調(diào)用超類的構(gòu)造
方法。接上例:
class C extends A.B { C () { new A()。super (); // 這一句就
實現(xiàn)了對內(nèi)部類構(gòu)造方法的調(diào)用。 } }
構(gòu)造方法也可這樣寫:
C (A a ) { a.super(); } // 使用這個構(gòu)造方法創(chuàng)建對象,要寫成C
c = new C (a ); a是A 的對象。
11、異常類
JAVA中除了RunTimeException類,其他異常均須捕獲或拋出。