2010年7月29日
#
Sun推出的專業(yè)認(rèn)證包括下列三種:
◆JAVA認(rèn)證考試
對于JAVA程序設(shè)計員,Sun推出兩項認(rèn)證:
Sun Certified JAVA Programmer(SCJP)
Sun Certified JAVA Developer(SCJD)
Java程序員的認(rèn)證Sun Certified JAVA Programmer(SCJP)課程:SL-275JAVA語言編程,考試號為310-025.
java開發(fā)員認(rèn)證Sun Certified JAVA Deverloper(SCJD),認(rèn)證考試以Sun指定的javaSL-285為教材,機(jī)考部分的考試號為310-027。
SCJP測驗JAVA程序設(shè)計概念及能力,內(nèi)容偏重于JAVA語法及JDK的內(nèi)容;SCJD則進(jìn)一步測試用JAVA開發(fā)應(yīng)用程序的能力,考試者必須先完成一個程序的設(shè)計方案,再回答與此方案相關(guān)的一些問題。
◆Solaris系統(tǒng)管理認(rèn)證考試
對Solaris/SunOS系統(tǒng)管理員,Sun推出Certified Solaris Administrator(CSA)。CSA分別為兩個等級(PartI和PartII),測試對Solaris系統(tǒng)管理的了解程度。
◆Solaris網(wǎng)絡(luò)管理認(rèn)證考試
為了測試使用者對于Solaris網(wǎng)絡(luò)管理能力,Sun推出Certified Network Administrator(CNA)。內(nèi)容包括基本網(wǎng)絡(luò)概念、RoutingandSubnet、Security、Performance、DNS、NIS+等。
SunJava認(rèn)證是業(yè)界唯一經(jīng)Sun授權(quán)Java認(rèn)證培訓(xùn)。Sun認(rèn)證Java開發(fā)員考試內(nèi)容包括完整的Java應(yīng)用程序開發(fā),涉及數(shù)據(jù)庫、圖形用戶界面、網(wǎng)絡(luò)通信、平臺移植等各方面內(nèi)容,要求學(xué)員已通過Java程序員認(rèn)證。學(xué)習(xí)結(jié)束后,可參加全球連網(wǎng)考試。考試合格則由Sun公司頒發(fā)國際通用的Java開發(fā)員證書。
Java語言在1995年發(fā)布以來,因其具有簡單性、跨平臺、面向?qū)ο蟮忍攸c,受到程序員們的歡迎,經(jīng)過這幾年的迅速發(fā)展,現(xiàn)在已經(jīng)成為和C++語言并列的主流開發(fā)語言。Java語言的廣泛使用,使得越來越多的人加入到Java語言的學(xué)習(xí)和應(yīng)用中來。
在這些人當(dāng)中,許多人選擇了經(jīng)過Sun公司授權(quán)的Sun教育中心(ASEC)來學(xué)習(xí),因為和一些非授權(quán)的中心相比,只有ASEC受到Sun組合機(jī)床公司的關(guān)注和支持,他們可以提供最新的培訓(xùn)材料和Sun需要的精深技術(shù)資源。學(xué)員在那里可以學(xué)習(xí)到最新的Java技術(shù),更順利地通過SunJava的認(rèn)證考試。
了解SunJava認(rèn)證課程
Java不僅僅是一種編程語言,同時它也是一個開發(fā)和運(yùn)行的平臺,有自己完整的體系結(jié)構(gòu)。SunJava認(rèn)證課程從中選擇了最具有代表性的一些方面。
SCJP(Sun Certified Java Programmer)可以說是各種Java認(rèn)證的基礎(chǔ),其對應(yīng)的最主要的學(xué)習(xí)課程是一門Java的基礎(chǔ)課程,也就是Java Programming Language(SL-275),這也是國內(nèi)的SCJP培訓(xùn)的標(biāo)準(zhǔn)課程。而SCJD(Sun Certified Java Developer)則可以看做是高級的Java技術(shù)培訓(xùn)認(rèn)證,其要求和難度都要高于SCJP,而且,如果你計劃獲得SCJD認(rèn)證,則要先獲得SCJP認(rèn)證資格。SCEA(Sun Certified Enterprise Architect for J2EE Technology)認(rèn)證的難度也不小,其學(xué)習(xí)課程主要有兩個:00-226O bject-Oriented Analysisand Design以及SL-425 Architectingand Designing J2EE Applications。SCWD(Sun Certified WebComponent Developer for Java2 Platform Enterprise Edition)是Sun新推出的Java認(rèn)證考試,主要面向使用JavaServlet以及JSP技術(shù)開發(fā)Web應(yīng)用程序的相關(guān)技術(shù)認(rèn)證。
如何獲取Java認(rèn)證
首先,你需要有充分的心理準(zhǔn)備,因為SunJava認(rèn)證考試非常嚴(yán)謹(jǐn),需要你具備充足的實踐經(jīng)驗才可能通過。
數(shù)據(jù)庫連接池概述:
數(shù)據(jù)庫連接是一種關(guān)鍵的有限的昂貴的資源,這一點在多用戶的網(wǎng)頁應(yīng)用程序中體現(xiàn)得尤為突出。對數(shù)據(jù)庫連接的管理能顯著影響到整個應(yīng)用程序的伸縮性和健壯性,影響到程序的性能指標(biāo)。數(shù)據(jù)庫連接池正是針對這個問題提出來的。
數(shù)據(jù)庫連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫連接,它允許應(yīng)用程序重復(fù)使用一個現(xiàn)有的數(shù)據(jù)庫連接,而再不是重新建立一個;釋放空閑時間超過最大空閑時間的數(shù)據(jù)庫連接來避免因為沒有釋放數(shù)據(jù)庫連接而引起的數(shù)據(jù)庫連接遺漏。這項技術(shù)能明顯提高對數(shù)據(jù)庫操作的性能。
數(shù)據(jù)庫連接池在初始化時將創(chuàng)建一定數(shù)量的數(shù)據(jù)庫連接放到連接池中,這些數(shù)據(jù)庫連接的數(shù)量是由最小數(shù)據(jù)庫連接數(shù)來設(shè)定的。無論這些數(shù)據(jù)庫連接是否被使用,連接池都將一直保證至少擁有這么多的連接數(shù)量。連接池的最大數(shù)據(jù)庫連接干洗設(shè)備數(shù)量限定了這個連接池能占有的最大連接數(shù),當(dāng)應(yīng)用程序向連接池請求的連接數(shù)超過最大連接數(shù)量時,這些請求將被加入到等待隊列中。數(shù)據(jù)庫連接池的最小連接數(shù)和最大連接數(shù)的設(shè)置要考慮到下列幾個因素:
1) 最小連接數(shù)是連接池一直保持的數(shù)據(jù)庫連接,所以如果應(yīng)用程序?qū)?shù)據(jù)庫連接的使用量不大,將會有大量的數(shù)據(jù)庫連接資源被浪費(fèi);
2) 最大連接數(shù)是連接池能申請的最大連接數(shù),如果數(shù)據(jù)庫連接請求超過此數(shù),后面的數(shù)據(jù)庫連接請求將被加入到等待隊列中,這會影響之后的數(shù)據(jù)庫操作。
3) 如果最小連接數(shù)與最大連接數(shù)相差太大,那么最先的連接請求將會獲利,之后超過最小連接數(shù)量的連接請求等價于建立一個新的數(shù)據(jù)庫連接。不過,這些大于最小連接數(shù)的數(shù)據(jù)庫連接在使用完不會馬上被釋放,它將被放到連接池中等待重復(fù)使用或是空閑超時后被釋放。
目前常用的連接池有:C3P0、DBCP、Proxool
網(wǎng)上的評價是:
C3P0比較耗費(fèi)資源,效率方面可能要低一點。
DBCP在實踐中存在BUG,在某些種情會產(chǎn)生很多空連接不能釋放,Hibernate3.0已經(jīng)放棄了對其的支持。
Proxool的負(fù)面評價較少,現(xiàn)在比較推薦它,而且它還提供即時監(jiān)控連接池狀態(tài)的功能,便于發(fā)現(xiàn)連接泄漏的情況。
配置如下:
1、在spring配置文件中,一般在applicationContext.xml中
<bean id="DataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource" destroy-method="shutdown">
<property name="driver">
<value>oracle.jdbc.driver.OracleDriver</value>
</property>
<property name="driverUrl">
<value>jdbc:oracle:thin:xxxx/xxxx@192.168.0.XX:1521:server</value>
</property>
<property name="user">
<value>xxxx</value>
</property>
<property name="password">
<value>xxxx</value>
</property>
<property name="alias">
<value>server</value>
</property>
<property name="houseKeepingSleepTime">
<value>30000</value>
</property>
<property name="houseKeepingTestSql">
<value>select 1 from dual</value>
</property>
<property name="testBeforeUse">
<value>true</value>
</property>
<property name="testAfterUse">
<value>true</value>
</property>
<property name="prototypeCount">
<value>5</value>
</property>
<property name="maximumConnectionCount">
<value>400</value>
</property>
<property name="minimumConnectionCount">
<value>10</value>
</property>
<property name="statistics">
<value>1m,15m,1d</value>
</property>
<property name="statisticsLogLevel">
<value>ERROR</value>
</property>
<property name="trace">
<value>true</value>
</property>
<property name="verbose">
<value>false</value>
</property>
<property name="simultaneousBuildThrottle">
<value>1600</value>
</property>
<property name="maximumActiveTime">
<value>600000</value>
</property>
<property name="jmx">
<value>false</value>
</property>
</bean>
然后注入到sessionFactory中
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="DataSource"/>
</bean>
屬性列表說明:
fatal-sql-exception: 它是一個逗號分割的信息片段.當(dāng)一個SQL異常發(fā)生時,他的異常信息將與這個信息片段進(jìn)行比較.如果在片段中存在,那么這個異常將被認(rèn)為是個致命錯誤(Fatal SQL Exception ).這種情況下,數(shù)據(jù)庫連接將要被放棄.無論發(fā)生什么,這個異常將會被重擲以提供給消費(fèi)者.用戶最好自己配置一個不同的異常來拋出.
fatal-sql-exception-wrapper-class:正如上面所說,你最好配置一個不同的異常來重擲.利用這個屬性,用戶可以包裝SQLException,使他變成另外一個異常.這個異常或者繼承QLException或者繼承字RuntimeException.proxool自帶了2個實現(xiàn):'org.logicalcobwebs.proxool.FatalSQLException'和'org.logicalcobwebs.proxool.FatalRuntimeException'.后者更合適.
house-keeping-sleep-time: house keeper 保留線程處于睡眠狀態(tài)的最長時間,house keeper 的職責(zé)就是檢查各個連接的狀態(tài),并判斷是否需要銷毀或者創(chuàng)建.
house-keeping-test-sql: 如果發(fā)現(xiàn)了空閑的數(shù)據(jù)庫連接.house keeper 將會用這個語句來測試.這個語句最好非常快的被執(zhí)行.如果沒有定義,測試過程將會被忽略。
injectable-connection-interface: 允許proxool實現(xiàn)被代理的connection對象的方法.
injectable-statement-interface: 允許proxool實現(xiàn)被代理的Statement 對象方法.
injectable-prepared-statement-interface: 允許proxool實現(xiàn)被代理的PreparedStatement 對象方法.
injectable-callable-statement-interface: 允許proxool實現(xiàn)被代理的CallableStatement 對象方法.
jmx: 如果屬性為true,就會注冊一個消息Bean到j(luò)ms服務(wù),消息Bean對象名: "Proxool:type=Pool, name=<alias>". 默認(rèn)值為false.
jmx-agent-id: 一個逗號分隔的JMX代理列表(如使用MBeanServerFactory.findMBeanServer(String agentId)注冊的連接池。)這個屬性是僅當(dāng)"jmx"屬性設(shè)置為"true"才有效。所有注冊jmx服務(wù)器使用這個屬性是不確定的
jndi-name: 數(shù)據(jù)源的名稱
maximum-active-time: 如果housekeeper 檢測到某個線程的活動時間大于這個數(shù)值.它將會殺掉這個線程.所以確認(rèn)一下你的服務(wù)器的帶寬.然后定一個合適的值.默認(rèn)是5分鐘.
maximum-connection-count: 最大的數(shù)據(jù)庫連接數(shù).
maximum-connection-lifetime: 一個線程的最大壽命.
minimum-connection-count: 最小的數(shù)據(jù)庫連接數(shù)
overload-without-refusal-lifetime: 這可以幫助我們確定連接池的狀態(tài)。如果我們已經(jīng)拒絕了一個連接在這個設(shè)定值(毫秒),然后被認(rèn)為是超載。默認(rèn)為60秒。
prototype-count: 連接池中可用的連接數(shù)量.如果當(dāng)前的連接池中的連接少于這個數(shù)值.新的連接將被建立(假設(shè)沒有超過最大可用數(shù)).例如.我們有3個活動連接2個可用連接,而我們的prototype-count是4,那么數(shù)據(jù)庫連接池將試圖建立另外2個連接.這和 minimum-connection-count不同. minimum-connection-count把活動的連接也計算在內(nèi).prototype-count 是spare connections 的數(shù)量.
recently-started-threshold: 這可以幫助我們確定連接池的狀態(tài),連接數(shù)少還是多或超載。只要至少有一個連接已開始在此值(毫秒)內(nèi),或者有一些多余的可用連接,那么我們假設(shè)連接池是開啟的。默認(rèn)為60秒
simultaneous-build-throttle: 這是我們可一次建立的最大連接數(shù)。那就是新增的連接請求,但還沒有可供使用的連接。由于連接可以使用多線程,在有限的時間之間建立聯(lián)系從而帶來可用連接,但是我們需要通過一些方式確認(rèn)一些線程并不是立即響應(yīng)連接請求的,默認(rèn)是10。
statistics: 連接池使用狀況統(tǒng)計。 參數(shù)“10s,1m,1d”
statistics-log-level: 日志統(tǒng)計跟蹤類型。 參數(shù)“ERROR”或 “INFO”
test-before-use: 如果為true,在每個連接被測試前都會服務(wù)這個連接,如果一個連接失敗,那么將被丟棄,另一個連接將會被處理,如果所有連接都失敗,一個新的連接將會被建立。否則將會拋出一個SQLException異常。
test-after-use: 如果為true,在每個連接被測試后都會服務(wù)這個連接,使其回到連接池中,如果連接失敗,那么將被廢棄。
trace: 如果為true,那么每個被執(zhí)行的SQL語句將會在執(zhí)行期被log記錄(DEBUG LEVEL).你也可以注冊一個ConnectionListener (參看ProxoolFacade)得到這些信息.
verbose: 詳細(xì)信息設(shè)置。 參數(shù) bool 值
1、Metal風(fēng)格 (默認(rèn))
String lookAndFeel = "javax.swing.plaf.metal.MetalLookAndFeel";
UIManager.setLookAndFeel(lookAndFeel);
2、Windows風(fēng)格
String lookAndFeel = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
UIManager.setLookAndFeel(lookAndFeel);
3、Windows Classic風(fēng)格
String lookAndFeel = "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel";
UIManager.setLookAndFeel(lookAndFeel);
4、Motif風(fēng)格
String lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
UIManager.setLookAndFeel(lookAndFeel);
5、Mac風(fēng)格 (需要在相關(guān)的操作系統(tǒng)上方可實現(xiàn))
String lookAndFeel = "com.sun.java.swing.plaf.mac.MacLookAndFeel";
UIManager.setLookAndFeel(lookAndFeel);
6、GTK風(fēng)格 (需要在相關(guān)的操作系統(tǒng)上方可實現(xiàn))
String lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
UIManager.setLookAndFeel(lookAndFeel);
7、可跨平臺的默認(rèn)風(fēng)格
String lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();
UIManager.setLookAndFeel(lookAndFeel);
8、當(dāng)前系統(tǒng)的風(fēng)格
String lookAndFeel = UIManager.getSystemLookAndFeelClassName();
UIManager.setLookAndFeel(lookAndFeel);
在Java中讓用戶能夠動態(tài)地更改應(yīng)用的外觀,可以給用戶更好地體驗,具體的實現(xiàn)方式是:
1,先使用UIManager.setLookAndFeel(String s)方法設(shè)定對應(yīng)的外觀
2,再使用SwingUtilities.updateComponentTreeUI(Component c)方法立刻更新應(yīng)用的外觀
這兩個類均在javax.swing包中
相關(guān)文章博客:睫晉姬 睫晉姬 睫晉姬 睫晉姬 睫晉姬 睫晉姬 睫晉姬 睫晉姬
Java多線程支持需要我們不斷的進(jìn)行相關(guān)問題的解決,下面我們就來看看在接口問題上的相關(guān)問題解決方案,這樣才能更好的進(jìn)行不斷的干洗機(jī)創(chuàng)新和學(xué)習(xí)。希望大家有所了解。
Java多線程支持,所有實現(xiàn)Runnable接口的類都可被啟動一個新線程,新線程會執(zhí)行該實例的run()方法,當(dāng)run()方法執(zhí)行完畢后,線程就結(jié)束了。一旦一個線程執(zhí)行完畢,這個實例就不能再重新啟動,只能重新生成一個新實例,再啟動一個新線程。
Thread類是實現(xiàn)了Runnable接口的一個實例,它代表一個線程的實例,并且,啟動線程的唯一方法就是通過Thread類的start()實例方法:
1.Thread t = new Thread();
2.t.start();
start()方法是一個native方法,它將啟動一個新線程,并執(zhí)行run()方法。Thread類默認(rèn)的run()方法什么也不做就退出了。注意:直接調(diào)用run()方法并不會啟動一個新線程,它和調(diào)用一個普通的java多線程支持方法沒有什么區(qū)別。
因此,有兩個方法可以實現(xiàn)自己的線程:
方法1:自己的類extend Thread,并復(fù)寫run()方法,就可以啟動新線程并執(zhí)行自己定義的run()方法。例如:
3.public class MyThread extends Thread {
4.public run() {
5.System.out.println("MyThread.run()");
6.}
7.}
在合適的地方啟動線程:new MyThread().start();
方法2:如果自己的類已經(jīng)extends另一個類,就無法直接extends Thread,此時,必須實現(xiàn)一個Runnable接口:
8.public class MyThread extends OtherClass implements Runnable {
9.public run() {
10.System.out.println("MyThread.run()");
11.}
12.}
為了啟動MyThread,需要首先實例化一個Thread,并傳入自己的MyThread實例:
13.MyThread myt = new MyThread();
14.Thread t = new Thread(myt);
15.t.start();
事實上,當(dāng)傳入一個Runnable target參數(shù)給Thread后,Thread的run()方法就會調(diào)用target.run(),參考JDK源代碼:
16.public void run() {
17.if (target != null) {
18.target.run();
19.}
20.}
Java多線程支持還有一些Name, ThreadGroup, isDaemon等設(shè)置,由于和線程設(shè)計模式關(guān)聯(lián)很少,這里就不多說了。
Java多線程特性為構(gòu)建高性能的應(yīng)用提供了極大的方便,但是也帶來了不少的麻煩。線程間同步、數(shù)據(jù)一致性等煩瑣的問題需要細(xì)心的考慮,一不小心就會出現(xiàn)一些微妙的,難以調(diào)試的錯誤。
另外,應(yīng)用邏輯和線程邏輯糾纏在一起,會導(dǎo)致程序的邏輯結(jié)構(gòu)混亂,難以復(fù)用和維護(hù)。本文試圖給出一個解決這個問題的方案,通過構(gòu)建一個并發(fā)模型框架(framework),使得開發(fā)多線程的應(yīng)用變得容易。
基礎(chǔ)知識
Java語言提供了對于線程很好的支持,實現(xiàn)方法小巧、優(yōu)雅。對于方法重入的保護(hù),信號量(semaphore)和臨界區(qū)(critical section)機(jī)制的實現(xiàn)都非常簡潔。可以很容易的實現(xiàn)多線程間的同步操作從而保護(hù)關(guān)鍵數(shù)據(jù)的一致性。這些特點使得Java成為面向?qū)ο笳Z言中對于多線程特性支持方面的佼佼者(C++正在試圖把boost庫中的對于線程的支持部分納入語言標(biāo)準(zhǔn))。
Java中內(nèi)置了對于對象并發(fā)訪問的支持,每一個對象都有一個監(jiān)視器(monitor),同時只允許一個線程持有監(jiān)視器從而進(jìn)行對對象的訪問,那些沒有獲得監(jiān)視器的線程必須等待直到持有監(jiān)視器的線程釋放監(jiān)視器。對象通過synchronized關(guān)鍵字來聲明線程必須獲得監(jiān)視器才能進(jìn)行對自己的訪問。
synchronized聲明僅僅對于一些較為簡單的線程間同步問題比較有效,對于哪些復(fù)雜的同步問題,比如帶有條件的同步問題,Java提供了另外的解決方法,wait/notify/notifyAll。
獲得對象監(jiān)視器的線程可以通過調(diào)用該對象的wait方法主動釋放監(jiān)視器,等待在該對象的線程等待隊列上,此時其他線程可以得到中頻點焊機(jī)監(jiān)視器從而訪問該對象,之后可以通過調(diào)用notify/notifyAll方法來喚醒先前因調(diào)用wait方法而等待的線程。
一般情況下,對于wait/notify/notifyAll方法的調(diào)用都是根據(jù)一定的條件來進(jìn)行的,比如:經(jīng)典的生產(chǎn)者/消費(fèi)者問題中對于隊列空、滿的判斷。熟悉POSIX的讀者會發(fā)現(xiàn),使用wait/notify/notifyAll可以很容易的實現(xiàn)POSIX中的一個線程間的高級同步技術(shù):條件變量。
簡單例子
本文將圍繞一個簡單的例子展開論述,這樣可以更容易突出我們解決問題的思路、方法。本文想向讀者展現(xiàn)的正是這些思路、方法。這些思路、方法更加適用于解決大規(guī)模、復(fù)雜應(yīng)用中的并發(fā)問題。考慮一個簡單的例子,我們有一個服務(wù)提供者,它通過一個接口對外提供服務(wù),服務(wù)內(nèi)容非常簡單,就是在標(biāo)準(zhǔn)輸出上打印Hello World。類結(jié)構(gòu)圖如下:

代碼如下:
1.interface Service
2.{
3. public void sayHello();
4.}
5.class ServiceImp implements Service
6.{
7. public void sayHello() {
8. System.out.println("Hello World!");
9. }
10.}
11.class Client
12.{
13. public Client(Service s) {
14. _service = s;
15.}
16. public void requestService() {
17. _service.sayHello();
18. }
19. private Service _service;
20.}
如果現(xiàn)在有新的需求,要求該服務(wù)必須支持Client的并發(fā)訪問。一種簡單的方法就是在ServicImp類中的每個方法前面加上synchronized聲明,來保證自己內(nèi)部數(shù)據(jù)的一致性(當(dāng)然對于本例來說,目前是沒有必要的,因為ServiceImp沒有需要保護(hù)的數(shù)據(jù),但是隨著需求的變化,以后可能會有的)。但是這樣做至少會存在以下幾個問題:
1.現(xiàn)在要維護(hù)ServiceImp的兩個版本:多線程版本和單線程版本(有些地方,比如其他項目,可能沒有并發(fā)的問題),容易帶來點凸焊機(jī)同步更新和正確選擇版本的問題,給維護(hù)帶來麻煩。
2.如果多個并發(fā)的Client頻繁調(diào)用該服務(wù),由于是直接同步調(diào)用,會造成Client阻塞,降低服務(wù)質(zhì)量。
3.很難進(jìn)行一些靈活的控制,比如:根據(jù)Client的優(yōu)先級進(jìn)行排隊等等。
4.這些問題對于大型的多線程應(yīng)用服務(wù)器尤為突出,對于一些簡單的應(yīng)用(如本文中的例子)可能根本不用考慮。本文正是要討論這些問題的解決方案,文中的簡單的例子只是提供了一個說明問題,展示思路、方法的平臺。
5.如何才能較好的解決這些問題,有沒有一個可以重用的解決方案呢?讓我們先把這些問題放一放,先來談?wù)労涂蚣苡嘘P(guān)的一些問題。
框架概述
熟悉面向?qū)ο蟮淖x者一定知道面向?qū)ο蟮淖畲蟮膬?yōu)勢之一就是:軟件復(fù)用。通過復(fù)用,可以減少很多的工作量,提高軟件開發(fā)生產(chǎn)率。復(fù)用本身也是分層次的,代碼級的復(fù)用和設(shè)計架構(gòu)的復(fù)用。
大家可能非常熟悉C語言中的一些標(biāo)準(zhǔn)庫,它們提供了一些通用的功能讓你的程序使用。但是這些標(biāo)準(zhǔn)庫并不能影響你的程序結(jié)構(gòu)和設(shè)計思路,僅僅是提供一些機(jī)能,幫助你的程序完成工作。它們使你不必重頭編寫一般性的通用功能(比如printf),它們強(qiáng)調(diào)的是程序代碼本身的復(fù)用性,而不是設(shè)計架構(gòu)的復(fù)用性。
那么什么是框架呢?所謂框架,它不同于一般的標(biāo)準(zhǔn)庫,是指一組緊密關(guān)聯(lián)的(類)classes,強(qiáng)調(diào)彼此的配合以完成某種可以重復(fù)運(yùn)用的設(shè)計概念。這些類之間以特定的方式合作,彼此不可或缺。它們相當(dāng)程度的影響了你的程序的形貌。框架本身規(guī)劃了應(yīng)用程序的骨干,讓程序遵循一定的流程和動線,展現(xiàn)一定的風(fēng)貌和功能。這樣就使程序員不必費(fèi)力于通用性的功能的繁文縟節(jié),集中精力于專業(yè)領(lǐng)域。
有一點必須要強(qiáng)調(diào),放之四海而皆準(zhǔn)的框架是不存在的,也是最沒有用處的。框架往往都是針對某個特定應(yīng)用領(lǐng)域的,是在對這個應(yīng)用領(lǐng)域進(jìn)行深刻理解的基礎(chǔ)上,抽象出該應(yīng)用的概念模型,在這些抽象的概念上搭建的一個模型,是一個有形無體的框架。不同的具體應(yīng)用根據(jù)自身的特點對框架中的抽象概念進(jìn)行實現(xiàn),從而賦予框架生命,完成應(yīng)用的功能。
基于框架的應(yīng)用都有兩部分構(gòu)成:框架部分和特定應(yīng)用部分。要想達(dá)到框架復(fù)用的目標(biāo),必須要做到框架部分和特定應(yīng)用部分的隔離。使用面向?qū)ο蟮囊粋€強(qiáng)大功能:多態(tài),可以實現(xiàn)這一點。在框架中完成抽象概念之間的交互、關(guān)聯(lián),把具體的實現(xiàn)交給特定的應(yīng)用來完成。其中一般都會大量使用了Template Method設(shè)計模式。Java中的Collection Framework以及微軟的MFC都是框架方面很好的例子。有興趣的讀者可以自行研究。
構(gòu)建框架
如何構(gòu)建一個Java并發(fā)模型框架呢?讓我們先回到原來的問題,先來分析一下原因。造成要維護(hù)多線程和單線程兩個版本的原因是由于把應(yīng)用邏輯和并發(fā)邏輯混在一起,如果能夠做到把應(yīng)用邏輯和并發(fā)模型進(jìn)行很好的隔離,那么應(yīng)用邏輯本身就可以很好的被復(fù)用,而且也很容易把并發(fā)邏輯添加進(jìn)來而不會對應(yīng)用邏輯造成任何影響。造成Client阻塞,性能降低以及無法進(jìn)行額外的控制的原因是由于所有的服務(wù)調(diào)用都是同步的,解決方案很簡單,改為異步調(diào)用方式,把服務(wù)的調(diào)用和服務(wù)的執(zhí)行分離。
首先來介紹一個概念,活動對象(Active Object)。所謂活動對象是相對于被動對象(passive object)而言的,被動對象的方法的調(diào)用和執(zhí)行都是在同一個線程中的,被動對象方法的調(diào)用是同步的、阻塞的,一般的對象都屬于被動對象;主動對象的方法的調(diào)用和執(zhí)行是分離的,主動對象有自己獨立的執(zhí)行線程,主動對象的上海保潔公司方法的調(diào)用是由其他線程發(fā)起的,但是方法是在自己的線程中執(zhí)行的,主動對象方法的調(diào)用是異步的,非阻塞的。
本框架的核心就是使用主動對象來封裝并發(fā)邏輯,然后把Client的請求轉(zhuǎn)發(fā)給實際的服務(wù)提供者(應(yīng)用邏輯),這樣無論是Client還是實際的服務(wù)提供者都不用關(guān)心并發(fā)的存在,不用考慮并發(fā)所帶來的數(shù)據(jù)一致性問題。從而實現(xiàn)應(yīng)用邏輯和并發(fā)邏輯的隔離,服務(wù)調(diào)用和服務(wù)執(zhí)行的隔離。下面給出關(guān)鍵的實現(xiàn)細(xì)節(jié)。
本框架有如下幾部分構(gòu)成:
1.一個ActiveObject類,從Thread繼承,封裝了并發(fā)邏輯的活動對象;
2.一個ActiveQueue類,主要用來存放調(diào)用者請求;
3.一個MethodRequest接口,主要用來封裝調(diào)用者的請求,Command設(shè)計模式的一種實現(xiàn)方式。它們的一個簡單的實現(xiàn)如下:
1. //MethodRequest接口定義
2. interface MethodRequest
3.{
4. public void call();
5.}
6.//ActiveQueue定義,其實就是一個producer/consumer隊列
7. class ActiveQueue
8.{
9. public ActiveQueue() {
10. _queue = new Stack();
11. }
12. public synchronized void enqueue(MethodRequest mr) {
13. while(_queue.size() > QUEUE_SIZE) {
14. try {
15. wait();
16. }catch (InterruptedException e) {
17. e.printStackTrace();
18. }
19. }
20.
21. _queue.push(mr);
22. notifyAll();
23. System.out.println("Leave Queue");
24. }
25. public synchronized MethodRequest dequeue() {
26. MethodRequest mr;
27.
28. while(_queue.empty()) {
29. try {
30. wait();
31. }catch (InterruptedException e) {
32. e.printStackTrace();
33. }
34. }
35. mr = (MethodRequest)_queue.pop();
36. notifyAll();
37.
38. return mr;
39. }
40. private Stack _queue;
41. private final static int QUEUE_SIZE = 20;
42.}
43.//ActiveObject的定義
44.class ActiveObject extends Thread
45.{
46. public ActiveObject() {
47. _queue = new ActiveQueue();
48. start();
49. }
50. public void enqueue(MethodRequest mr) {
51. _queue.enqueue(mr);
52. }
53. public void run() {
54. while(true) {
55. MethodRequest mr = _queue.dequeue();
56. mr.call();
57. }
58. }
59. private ActiveQueue _queue;
60.}
通過上面的代碼可以看出正是這些類相互合作完成了對并發(fā)邏輯的封裝。開發(fā)者只需要根據(jù)需要實現(xiàn)MethodRequest接口,另外再定義一個服務(wù)代理類提供給使用者,在服務(wù)代理者類中把服務(wù)調(diào)用者的請求轉(zhuǎn)化為MethodRequest實現(xiàn),交給活動對象即可。
使用該框架,可以較好的做到應(yīng)用邏輯和并發(fā)模型的分離,從而使開發(fā)者集中精力于應(yīng)用領(lǐng)域,然后平滑的和并發(fā)模型結(jié)合起來,并且可以針對ActiveQueue定制排隊機(jī)制,比如基于優(yōu)先級等。
基于框架的解決方案
本小節(jié)將使用上述的框架重新實現(xiàn)前面的例子,提供對于并發(fā)的支持。第一步先完成對于MethodRequest的實現(xiàn),對于我們的例子來說實現(xiàn)如下:
1.class SayHello implements MethodRequest
2.{
3. public SayHello(Service s) {
4. _service = s;
5. }
6. public void call() {
7. _service.sayHello();
8. }
9. private Service _service;
10.}
該類完成了對于服務(wù)提供接口sayHello方法的封裝。接下來定義一個服務(wù)代理類,來完成請求的封裝、排隊功能,當(dāng)然為了做到對Client透明,該類必須實現(xiàn)Service接口。定義如下:
11.class ServiceProxy implements Service
12.{
13. public ServiceProxy() {
14. _service = new ServiceImp();
15. _active_object = new ActiveObject();
16. }
17.
18. public void sayHello() {
19. MethodRequest mr = new SayHello(_service);
20. _active_object.enqueue(mr);
21. }
22. private Service _service;
23. private ActiveObject _active_object;
24.}
其他的類和接口定義不變,下面對比一下并發(fā)邏輯增加前后的服務(wù)調(diào)用的變化,并發(fā)邏輯增加前,對于sayHello服務(wù)的調(diào)用方法:
25.Service s = new ServiceImp();
26.Client c = new Client(s);
27.c.requestService();
并發(fā)邏輯增加后,對于sayHello服務(wù)的調(diào)用方法:
28.Service s = new ServiceProxy();
29.Client c = new Client(s);
30.c.requestService();
可以看出并發(fā)邏輯增加前后對于Client的ServiceImp都無需作任何改變,使用方式也非常一致,ServiceImp也能夠獨立的進(jìn)行重用。類結(jié)構(gòu)圖如下:

讀者容易看出,使用框架也增加了一些復(fù)雜性,對于一些簡單的應(yīng)用來說可能根本就沒有必要使用本框架。希望讀者能夠根據(jù)自己的實際情況進(jìn)行判斷。
結(jié)論
本文圍繞一個簡單的例子論述了如何構(gòu)架一個Java并發(fā)模型框架,其中使用了一些構(gòu)建框架的常用技術(shù),當(dāng)然所構(gòu)建的框架和一些成熟的商用框架相比,顯得非常稚嫩,比如沒有考慮服務(wù)調(diào)用有返回值的情況,但是其思想方法是一致的,希望讀者能夠深加領(lǐng)會,這樣無論對于構(gòu)建自己的框架還是理解一些其他的框架都是很有幫助的。讀者可以對本文中的框架進(jìn)行擴(kuò)充,直接應(yīng)用到自己的工作中。
優(yōu)點:
1.增強(qiáng)了應(yīng)用的并發(fā)性,簡化了同步控制的復(fù)雜性;
2.服務(wù)的請求和服務(wù)的執(zhí)行分離,使得可以對服務(wù)請求排隊,進(jìn)行靈活的控制;
3.應(yīng)用邏輯和并發(fā)模型分離,使得程序結(jié)構(gòu)清晰,易于維護(hù)、重用;
4.可以使開發(fā)者集中精力于應(yīng)用領(lǐng)域。
缺點:
1.由于框架所需類的存在,在一定程度上增加了程序的復(fù)雜性;
2.如果應(yīng)用需要過多的活動對象,由于線程切換開銷會造成性能下降;
3.可能會造成調(diào)試?yán)щy。
在Java語言產(chǎn)生前,傳統(tǒng)的程序設(shè)計語言的程序同一時刻只能單任務(wù)操作,效率非常低,例如程序往往在接收數(shù)據(jù)輸入時發(fā)生阻塞,只有等到程序獲得數(shù)據(jù)后才能繼續(xù)運(yùn)行。隨著Internet的迅猛發(fā)展,這種狀況越來越不能讓人們?nèi)淌埽喝绻W(wǎng)絡(luò)接收熱合機(jī)數(shù)據(jù)阻塞,后臺程序就處于等待狀態(tài)而不繼續(xù)任何操作,而這種阻塞是經(jīng)常會碰到的,此時CPU資源被白白的閑置起來。如果在后臺程序中能夠同時處理多個任務(wù),該多好啊!應(yīng)Internet技術(shù)而生的Java語言解決了這個問題,多線程程序是Java語言的一個很重要的特點。在一個Java程序中,我們可以同時并行運(yùn)行多個相對獨立的線程,例如,我們?nèi)绻麆?chuàng)建一個線程來進(jìn)行數(shù)據(jù)輸入輸出,而創(chuàng)建另一個線程在后臺進(jìn)行其它的數(shù)據(jù)處理,如果輸入輸出線程在接收數(shù)據(jù)時阻塞,而處理數(shù)據(jù)的線程仍然在運(yùn)行。多線程程序設(shè)計大大提高了程序執(zhí)行效率和處理能力。
線程的創(chuàng)建
我們知道Java是面向?qū)ο蟮某绦蛘Z言,用Java進(jìn)行程序設(shè)計就是設(shè)計和使用類,Java為我們提供了線程類Thread來創(chuàng)建線程,創(chuàng)建線程與創(chuàng)建普通的類的對象的操作是一樣的,而線程就是Thread類或其子類的實例對象。下面是一個創(chuàng)建啟動一個線程的語句:
Thread thread1=new Thread(); file://聲明一個對象實例,即創(chuàng)建一個線程;
Thread1.run(); file://用Thread類中的run()方法啟動線程;
從這個例子,我們可以通過Thread()構(gòu)造方法創(chuàng)建一個線程,并啟動該線程。事實上,啟動線程,也就是啟動線程的run()方法,而Thread類中的run()方法沒有任何操作語句,所以這個線程沒有任何操作。要使線程實現(xiàn)預(yù)定功能,必須定義自己的run()方法。Java中通常有兩種方式定義 run()方法:
通過定義一個Thread類的子類,在該子類中重寫run()方法。Thread子類的實例對象就是一個線程,顯然,該線程有我們自己設(shè)計的線程體run()方法,啟動線程就啟動了子類中重寫的run()方法。
通過Runnable接口,在該接口中定義run()方法的接口。所謂接口跟類非常類似,主要用來實現(xiàn)特殊功能,如復(fù)雜關(guān)系的多重繼承功能。在此,我們定義一個實現(xiàn)Runnable() 接口的類,在該類中定義自己的run()方法,然后以該類的實例對象為參數(shù)調(diào)用Thread類的構(gòu)造方法來創(chuàng)建一個線程。
線程被實際創(chuàng)建后處于待命狀態(tài),激活(啟動)線程就是啟動線程的run()方法,這是通過調(diào)用線程的start()方法來實現(xiàn)的。
下面一個例子實踐了如何通過上述兩種方法創(chuàng)建線程并啟動它們:
// 通過Thread類的子類創(chuàng)建的線程;
{ file://自定義線程的run()方法;
file://通過Runnable接口創(chuàng)建的另外一個線程;
{ file://自定義線程的run()方法;
file://程序的主類'
class Multi_Thread file://聲明主類;
plubic static void mail(String args[]) file://聲明主方法;
thread1 threadone=new thread1(); file://用Thread類的子類創(chuàng)建線程;
Thread threadtwo=new Thread(new thread2()); file://用Runnable接口類的對象創(chuàng)建線程;
threadone.start(); threadtwo.start(); file://strat()方法啟動線程;
運(yùn)行該程序就可以看出,線程threadone和threadtwo交替占用CPU,處于并行運(yùn)行狀態(tài)。可以看出,啟動線程的run()方法是通過調(diào)用線程的start()方法來實現(xiàn)的(見上例中主類),調(diào)用start()方法啟動線程的run()方法不同于一般的調(diào)用方法,調(diào)用一般方法時,必須等到一般方法執(zhí)行完畢才能夠返回start()方法,而啟動線程的run()方法后,start()告訴系統(tǒng)該線程準(zhǔn)備就緒可以啟動run()方法后,就返回 start()方法執(zhí)行調(diào)用start()方法語句下面的語句,這時run()方法可能還在運(yùn)行,這樣,線程的啟動和運(yùn)行并行進(jìn)行,實現(xiàn)了多任務(wù)操作。
線程的優(yōu)先級
對于多線程程序,每個線程的重要程度是不盡相同,如多個線程在等待獲得CPU時間時,往往我們需要優(yōu)先級高的線程優(yōu)先搶占到CPU時間得以執(zhí)行;又如多個線程交替執(zhí)行時,優(yōu)先級決定了級別高的線程得到CPU的次數(shù)多一些且時間多長一些;這樣,高優(yōu)先級的線程處理的任務(wù)效率就高一些。
Java中線程的優(yōu)先級從低到高以整數(shù)1~10表示,共分為10級,設(shè)置優(yōu)先級是通過調(diào)用線程對象的setPriority()方法,如上例中,設(shè)置優(yōu)先級的語句為:
thread1 threadone=new thread1(); file://用Thread類的子類創(chuàng)建線程;
Thread threadtwo=new Thread(new thread2()); file://用Runnable接口類的對象創(chuàng)建線程;
threadone.setPriority(6); file://設(shè)置threadone的優(yōu)先級6;
threadtwo.setPriority(3); file://設(shè)置threadtwo的優(yōu)先級3;
threadone.start(); threadtwo.start(); file://strat()方法啟動線程;
這樣,線程threadone將會優(yōu)先于線程threadtwo執(zhí)行,并將占有更多的CPU時間。該例中,優(yōu)先級設(shè)置放在線程啟動前,也可以在啟動后進(jìn)行設(shè)置,以滿足不同的優(yōu)先級需求。
線程的(同步)控制
一個Java程序的多線程之間可以共享數(shù)據(jù)。當(dāng)線程以異步方式訪問共享數(shù)據(jù)時,有時候是不安全的或者不和邏輯的。比如,同一時刻一個線程在讀取數(shù)據(jù),另外一個線程在處理數(shù)據(jù),當(dāng)處理數(shù)據(jù)的線程沒有等到讀取收縮機(jī)數(shù)據(jù)的線程讀取完畢就去處理數(shù)據(jù),必然得到錯誤的處理結(jié)果。這和我們前面提到的讀取數(shù)據(jù)和處理數(shù)據(jù)并行多任務(wù)并不矛盾,這兒指的是處理數(shù)據(jù)的線程不能處理當(dāng)前還沒有讀取結(jié)束的數(shù)據(jù),但是可以處理其它的數(shù)據(jù)。
如果我們采用多線程同步控制機(jī)制,等到第一個線程讀取完數(shù)據(jù),第二個線程才能處理該數(shù)據(jù),就會避免錯誤。可見,線程同步是多線程編程的一個相當(dāng)重要的技術(shù)。
在講線程的同步控制前我們需要交代如下概念:
1 用Java關(guān)鍵字synchonized同步對共享數(shù)據(jù)操作的方法
在一個對象中,用synchonized聲明的方法為同步方法。Java中有一個同步模型-監(jiān)視器,負(fù)責(zé)管理線程對對象中的同步方法的訪問,它的原理是:賦予該對象唯一一把'鑰匙',當(dāng)多個線程進(jìn)入對象,只有取得該對象鑰匙的線程才可以訪問同步方法,其它線程在該對象中等待,直到該線程用wait() 方法放棄這把鑰匙,其它等待的線程搶占該鑰匙,搶占到鑰匙的線程后才可得以執(zhí)行,而沒有取得鑰匙的線程仍被阻塞在該對象中等待。
file://聲明同步的一種方式:將方法聲明同步
class store
public synchonized void store_in()
public synchonized void store_out(){
2 利用wait()、notify()及notifyAll()方法發(fā)送消息實現(xiàn)線程間的相互聯(lián)系
Java程序中多個線程通過消息來實現(xiàn)互動聯(lián)系的,這幾種方法實現(xiàn)了線程間的消息發(fā)送。例如定義一個對象的synchonized 方法,同一時刻只能夠有一個線程訪問該對象中的同步方法,其它線程被阻塞。通常可以用notify()或notifyAll()方法喚醒其它一個或所有線程。而使用wait()方法來使該線程處于阻塞狀態(tài),等待其它的線程用notify()喚醒。
一個實際的例子就是生產(chǎn)和銷售,生產(chǎn)單元將產(chǎn)品生產(chǎn)出來放在倉庫中,銷售單元則從倉庫中提走產(chǎn)品,在這個過程中,銷售單元必須在倉庫中有產(chǎn)品時才能提貨;如果倉庫中沒有產(chǎn)品,則銷售單元必須等待。
程序中,假如我們定義一個倉庫類store,該類的實例對象就相當(dāng)于倉庫,在store類中定義兩個成員方法:store_in(),用來模擬產(chǎn)品制造者往倉庫中添加產(chǎn)品;strore_out()方法則用來模擬銷售者從倉庫中取走產(chǎn)品。然后定義兩個線程類:customer類,其中的run()方法通過調(diào)用倉庫類中的store_out()從倉庫中取走產(chǎn)品,模擬銷售者;另外一個線程類producer中的run()方法通過調(diào)用倉庫類中的 store_in()方法向倉庫添加產(chǎn)品,模擬產(chǎn)品制造者。在主類中創(chuàng)建并啟動線程,實現(xiàn)向倉庫中添加產(chǎn)品或取走產(chǎn)品。
如果倉庫類中的store_in() 和store_out()方法不聲明同步,這就是個一般的多線程,我們知道,一個程序中的多線程是交替執(zhí)行的,運(yùn)行也是無序的,這樣,就可能存在這樣的問題:
倉庫中沒有產(chǎn)品了,銷售者還在不斷光顧,而且還不停的在'取'產(chǎn)品,這在現(xiàn)實中是不可思義的,在程序中就表現(xiàn)為負(fù)值;如果將倉庫類中的stroe_in ()和store_out()方法聲明同步,如上例所示:就控制了同一時刻只能有一個線程訪問倉庫對象中的同步方法;即一個生產(chǎn)類線程訪問被聲明為同步的 store_in()方法時,其它線程將不能夠訪問對象中的store_out()同步方法,當(dāng)然也不能訪問store_in()方法。必須等到該線程調(diào)用wait()方法放棄鑰匙,其它線程才有機(jī)會訪問同步方法。
Java代碼
1.package com.zbalpha.test;
2.
3.import java.util.ArrayList;
4.import java.util.Iterator;
5.import java.util.List;
6.
7.public class ListTest {
8. public static void main(String args[]){
9. List<Long> lists = new ArrayList<Long>();
10.
11. for(Long i=0l;i<1000000l;i++){
12. lists.add(i);
13. }
14.
15. Long oneOk = oneMethod(lists);
16. Long twoOk = twoMethod(lists);
17. Long threeOk = threeMethod(lists);
18. Long fourOk = fourMethod(lists);
19.
20. System.out.println("One:" + oneOk);
21. System.out.println("Two:" + twoOk);
22. System.out.println("Three:" + threeOk);
23. System.out.println("four:" + fourOk);
24.
25. }
26.
27. public static Long oneMethod(List<Long> lists){
28.
29. Long timeStart = System.currentTimeMillis();
30. for(int i=0;i<lists.size();i++) {
31. System.out.println(lists.get(i));
32. }
33. Long timeStop = System.currentTimeMillis();
34.
35. return timeStop -timeStart ;
36. }
37.
38. public static Long twoMethod(List<Long> lists){
39.
40. Long timeStart = System.currentTimeMillis();
41. for(Long string : lists) {
42. System.out.println(string);
43. }
44. Long timeStop = System.currentTimeMillis();
45.
46. return timeStop -timeStart ;
47. }
48.
49. public static Long threeMethod(List<Long> lists){
50.
51. Long timeStart = System.currentTimeMillis();
52. Iterator<Long> it = lists.iterator();
53. while (it.hasNext())
54. {
55. System.out.println(it.next());
56. }
57. Long timeStop = System.currentTimeMillis();
58.
59. return timeStop -timeStart ;
60. }
61.
62.
63.
64. public static Long fourMethod(List<Long> lists){
65.
66. Long timeStart = System.currentTimeMillis();
67. for(Iterator<Long> i = lists.iterator(); i.hasNext();) {
68. System.out.println(i.next());
69. }
70. Long timeStop = System.currentTimeMillis();
71.
72. return timeStop -timeStart ;
73. }
74.}
容器類可以大大提高編程效率和編程能力,在Java2中,所有的容器都由SUN公司的Joshua Bloch進(jìn)行了重新設(shè)計,豐富了容器類庫的功能。
Java2容器類類庫的用途是“保存對象”,它分為兩類:
Collection----一組獨立的元素,通常這些元素都服從某種規(guī)則。List必須保持元素特定的順序,而Set不能有重復(fù)元素。
Map----一組成對的“鍵值對”對象,即其元素是成對的對象,最典型的應(yīng)用就是數(shù)據(jù)字典,并且還有其它廣泛的應(yīng)用。另外,Map可以返回其所有鍵豐胸組成的Set和其所有值組成的Collection,或其鍵值對組成的Set,并且還可以像數(shù)組一樣擴(kuò)展多維Map,只要讓Map中鍵值對的每個 “值”是一個Map即可。
1.迭代器
迭代器是一種設(shè)計模式,它是一個對象,它可以遍歷并選擇序列中的對象,而開發(fā)人員不需要了解該序列的底層結(jié)構(gòu)。迭代器通常被稱為“輕量級”對象,因為創(chuàng)建它的代價小。
Java中的Iterator功能比較簡單,并且只能單向移動:
(1) 使用方法iterator()要求容器返回一個Iterator。第一次調(diào)用Iterator的next()方法時,它返回序列的第一個元素。
(2) 使用next()獲得序列中的下一個元素。
(3) 使用hasNext()檢查序列中是否還有元素。
(4) 使用remove()將迭代器新返回的元素刪除。
Iterator是Java迭代器最簡單的實現(xiàn),為List設(shè)計的ListIterator具有更多的功能,它可以從兩個方向遍歷List,也可以從List中插入和刪除元素。
2.List的功能方法
List(interface): 次序是List最重要的特點;它確保維護(hù)元素特定的順序。List為Collection添加了許多方法,使得能夠向List中間插入與移除元素(只推薦 LinkedList使用)。一個List可以生成ListIterator,使用它可以從兩個方向遍歷List,也可以從List中間插入和刪除元素。
ArrayList: 由數(shù)組實現(xiàn)的List。它允許對元素進(jìn)行快速隨機(jī)訪問,但是向List中間插入與移除元素的速度很慢。ListIterator只應(yīng)該用來由后向前遍歷ArrayList,而不是用來插入和刪除元素,因為這比LinkedList開銷要大很多。
LinkedList: 對順序訪問進(jìn)行了優(yōu)化,向List中間插入與刪除得開銷不大,隨機(jī)訪問則相對較慢(可用ArrayList代替)。它具有方法addFirst()、 addLast()、getFirst()、getLast()、removeFirst()、removeLast(),這些方法(沒有在任何接口或基類中定義過)使得LinkedList可以當(dāng)作堆棧、隊列和雙向隊列使用。
3.Set的功能方法
Set(interface): 存入Set的每個元素必須是唯一的,因為Set不保存重復(fù)元素。加入Set的Object必須定義equals()方法以確保對象的唯一性。Set與Collection有完全一樣的接口。Set接口不保證維護(hù)元素的次序。
HashSet: 為快速查找而設(shè)計的Set。存入HashSet的對象必須定義hashCode()。
TreeSet: 保持次序的Set,底層為樹結(jié)構(gòu)。使用它可以從Set中提取有序的序列。
LinkedHashSet: 具有HashSet的查詢速度,且內(nèi)部使用鏈表維護(hù)元素的順序(插入的次序)。于是在使用迭代器遍歷Set時,結(jié)果會按元素插入的次序顯示。
HashSet采用散列函數(shù)對元素進(jìn)行排序,這是專門為快速查詢而設(shè)計的;TreeSet采用紅黑樹的數(shù)據(jù)結(jié)構(gòu)進(jìn)行排序元素;LinkedHashSet內(nèi)部使用散列以加快查詢速度,同時使用鏈表維護(hù)元素的次序,使得看起來元素是以插入的順序保存的。需要注意的是,生成自己的類時,Set需要維護(hù)元素的存儲順序,因此要實現(xiàn)Comparable接口并定義compareTo()方法。
在java編程思想中對synchronized的一點解釋:
1、synchronized關(guān)鍵字的作用域有二種:
1)是某個對象實例內(nèi),synchronized aMethod(){}可以防止多個線程同時訪問這個對象的synchronized方法(如果一個對象有多個synchronized方法,只要一個線程訪問了其中的一個synchronized方法,其它線程不能同時訪問這個對象中任何一個synchronized方法)。這時,不同的對象實例的synchronized方法是不相干擾的。也就是說,其它線程照樣可以同時訪問相同類的另一個對象實例中的synchronized方法;
2)是某個類的范圍,synchronized static aStaticMethod{}防止多個線程同時訪問這個類中的synchronized static 方法。它可以對類的所有對象實例起作用。
2、除了方法前用synchronized關(guān)鍵字,synchronized關(guān)鍵字還可以用于方法中的某個區(qū)塊中,表示只對這個區(qū)塊的資源實行互斥訪問。用法是: synchronized(this){/*區(qū)塊*/},它的作用域是當(dāng)前對象;
3、synchronized關(guān)鍵字是不能繼承的,也就是說,基類的方法synchronized f(){} 在繼承類中并不自動是synchronized f(){},而是變成了f(){}。繼承類需要你顯式的指定它的某個方法為synchronized方法;
----------------------------------------------------------------------------
java里面synchronized用法
synchronized的一個簡單例子
public class TextThread
{
/**
* @param args
*/
public static void main(String[] args)
{
// TODO 自動生成方法存根
TxtThread tt = new TxtThread();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
new Thread(tt).start();
}
}
class TxtThread implements Runnable
{
int num = 100;
String str = new String();
public void run()
{
while (true)
{
synchronized(str)
{
if (num>0)
{
try
{
Thread.sleep(10);
}
catch(Exception e)
{
e.getMessage();
}
System.out.println(Thread.currentThread().getName()+ "this is "+ num--);
}
}
}
}
}
上面的例子中為了制造一個時間差,也就是出錯的機(jī)會,使用了Thread.sleep(10)
Java對多線程的支持與衛(wèi)星電視同步機(jī)制深受大家的喜愛,似乎看起來使用了synchronized關(guān)鍵字就可以輕松地解決多線程共享數(shù)據(jù)同步問題。到底如何?――還得對synchronized關(guān)鍵字的作用進(jìn)行深入了解才可定論。
總的說來,synchronized關(guān)鍵字可以作為函數(shù)的修飾符,也可作為函數(shù)內(nèi)的語句,也就是平時說的同步方法和同步語句塊。如果再細(xì)的分類,synchronized可作用于instance變量、object reference(對象引用)、static函數(shù)和class literals(類名稱字面常量)身上。
在進(jìn)一步闡述之前,我們需要明確幾點:
A.無論synchronized關(guān)鍵字加在方法上還是對象上,它取得的鎖都是對象,而不是把一段代碼或函數(shù)當(dāng)作鎖――而且同步方法很可能還會被其他線程的對象訪問。
B.每個對象只有一個鎖(lock)與之相關(guān)聯(lián)。
C.實現(xiàn)同步是要很大的系統(tǒng)開銷作為代價的,甚至可能造成死鎖,所以盡量避免無謂的同步控制。
接著來討論synchronized用到不同地方對代碼產(chǎn)生的影響:
假設(shè)P1、P2是同一個類的不同對象,這個類中定義了以下幾種情況的同步塊或同步方法,P1、P2就都可以調(diào)用它們。
1. 把synchronized當(dāng)作函數(shù)修飾符時,示例代碼如下:
Public synchronized void methodAAA()
{
//….
}
這也就是同步方法,那這時synchronized鎖定的是哪個對象呢?它鎖定的是調(diào)用這個同步方法對象。也就是說,當(dāng)一個對象P1在不同的線程中執(zhí)行這個同步方法時,它們之間會形成互斥,達(dá)到同步的效果。但是這個對象所屬的Class所產(chǎn)生的另一對象P2卻可以任意調(diào)用這個被加了synchronized關(guān)鍵字的方法。
上邊的示例代碼等同于如下代碼:
public void methodAAA()
{
synchronized (this) // (1)
{
//…..
}
}
(1)處的this指的是什么呢?它指的就是調(diào)用這個方法的對象,如P1。可見同步方法實質(zhì)是將synchronized作用于object reference。――那個拿到了P1對象鎖的線程,才可以調(diào)用P1的同步方法,而對P2而言,P1這個鎖與它毫不相干,程序也可能在這種情形下擺脫同步機(jī)制的控制,造成數(shù)據(jù)混亂:(
2.同步塊,示例代碼如下:
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
這時,鎖就是so這個對象,誰拿到這個鎖誰就可以運(yùn)行它所控制的那段代碼。當(dāng)有一個明確的對象作為鎖時,就可以這樣寫程序,但當(dāng)沒有明確的對象作為鎖,只是想讓一段代碼同步時,可以創(chuàng)建一個特殊的instance變量(它得是一個對象)來充當(dāng)鎖:
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // 特殊的instance變量
Public void methodA()
{
synchronized(lock) { //… }
}
//…..
}
注:零長度的byte數(shù)組對象創(chuàng)建起來將比任何對象都經(jīng)濟(jì)――查看編譯后的字節(jié)碼:生成零長度的byte[]對象只需3條操作碼,而Object lock = new Object()則需要7行操作碼。
3.將synchronized作用于static 函數(shù),示例代碼如下:
Class Foo
{
public synchronized static void methodAAA() // 同步的static 函數(shù)
{
//….
}
public void methodBBB()
{
synchronized(Foo.class) // class literal(類名稱字面常量)
}
}
代碼中的methodBBB()方法是把class literal作為鎖的情況,它和同步的static函數(shù)產(chǎn)生的效果是一樣的,取得的鎖很特別,是當(dāng)前調(diào)用這個方法的衛(wèi)星電視對象所屬的類(Class,而不再是由這個Class產(chǎn)生的某個具體對象了)。
記得在《Effective Java》一書中看到過將 Foo.class和 P1.getClass()用于作同步鎖還不一樣,不能用P1.getClass()來達(dá)到鎖這個Class的目的。P1指的是由Foo類產(chǎn)生的對象。
可以推斷:如果一個類中定義了一個synchronized的static函數(shù)A,也定義了一個synchronized 的instance函數(shù)B,那么這個類的同一對象Obj在多線程中分別訪問A和B兩個方法時,不會構(gòu)成同步,因為它們的鎖都不一樣。A方法的鎖是Obj這個對象,而B的鎖是Obj所屬的那個Class。
小結(jié)如下:
搞清楚synchronized鎖定的是哪個對象,就能幫助我們設(shè)計更安全的多線程程序。
還有一些技巧可以讓我們對共享資源的同步訪問更加安全:
1. 定義private 的instance變量+它的 get方法,而不要定義public/protected的instance變量。如果將變量定義為public,對象在外界可以繞過同步方法的控制而直接取得它,并改動它。這也是JavaBean的標(biāo)準(zhǔn)實現(xiàn)方式之一。
2. 如果instance變量是一個對象,如數(shù)組或ArrayList什么的,那上述方法仍然不安全,因為當(dāng)外界對象通過get方法拿到這個instance對象的引用后,又將其指向另一個對象,那么這個private變量也就變了,豈不是很危險。 這個時候就需要將get方法也加上synchronized同步,并且,只返回這個private對象的clone()――這樣,調(diào)用端得到的就是對象副本的引用了。
JDK 5.0 中增加的泛型類型,是 Java 語言中類型安全的一次重要改進(jìn)。但是,對于初次使用泛型類型的用戶來說,泛型的某些方面看起來可能不容易明白,甚至非常奇怪。在本月的“Java 理論和實踐”中,Brian Goetz 分析了束縛第一次使用泛型的用戶的常見陷阱。您可以通過討論論壇與作者和其他讀者分享您對本文的看法。(也可以單擊本文頂端或底端的討論來訪問這個論壇。)
表面上看起來,無論語法還是應(yīng)用的環(huán)境(比如容器類),泛型類型(或者泛型)都類似于 C++ 中的模板。但是這種相似性僅限于表面,Java 語言中的泛型基本上完全在編譯器中實現(xiàn),由編譯器執(zhí)行類型檢查和類型推斷,然后生成普通的非泛型的字節(jié)碼。這種實現(xiàn)技術(shù)稱為擦除(erasure)(編譯器使用泛型類型信息保證類型安全,然后在生成字節(jié)碼之前將其清除),這項技術(shù)有一些奇怪,并且有時會帶來一些令人迷惑的后果。雖然范型是 Java 類走向類型安全的一大步,但是在學(xué)習(xí)使用泛型的過程中幾乎肯定會遇到頭痛(有時候讓人無法忍受)的問題。
注意:本文假設(shè)您對 JDK 5.0 中的范型有基本的了解。
泛型不是協(xié)變的
雖然將集合看作是數(shù)組的抽象會有所幫助,但是數(shù)組還有一些集合不具備的特殊性質(zhì)。Java 語言中的數(shù)組是協(xié)變的(covariant),也就是說,如果 Integer 擴(kuò)展了 Number(事實也是如此),那么不僅 Integer 是 Number,而且 Integer[] 也是 Number[],在要求 Number[] 的地方完全可以傳遞或者賦予 Integer[]。(更正式地說,如果 Number 是 Integer 的超類型,那么 Number[] 也是 Integer[] 的超類型)。您也許認(rèn)為這一原理同樣適用于泛型類型 —— List<Number> 是 List<Integer> 的超類型,那么可以在需要 List<Number> 的地方傳遞 List<Integer>。不幸的是,情況并非如此。
不允許這樣做有一個很充分的理由:這樣做將破壞要提供的類型安全泛型。如果能夠?qū)?List<Integer> 賦給 List<Number>。那么下面的代碼就允許將非 Integer 的內(nèi)容放入 List<Integer>:
List<Integer> li = new ArrayList<Integer nike jordan 2010>();
List<Number> ln = li; // illegal
ln.add(new Float(3.1415));
因為 ln 是 List<Number>,所以向其添加 Float 似乎是完全合法的。但是如果 ln 是 li 的別名,那么這就破壞了蘊(yùn)含在 li 定義中的類型安全承諾 —— 它是一個整數(shù)列表,這就是泛型類型不能協(xié)變的原因。
其他的協(xié)變問題
數(shù)組能夠協(xié)變而泛型不能協(xié)變的另一個后果是,不能實例化泛型類型的數(shù)組(new List<String>[3] 是不合法的),除非類型參數(shù)是一個未綁定的通配符(new List<?>[3] 是合法的)。讓我們看看如果允許聲明泛型類型數(shù)組會造成什么后果:
List<String>[] lsa = new List<String>[10]; // illegal
Object[] oa = lsa; // OK because List<String> is a subtype of Object
List<Integer> li = new ArrayList<Integer>();
li.add(new Integer(3));
oa[0] = li;
String s = lsa[0].get(0);
最后一行將拋出 ClassCastException,因為這樣將把 List<Integer> 填入本應(yīng)是 List<String> 的位置。因為數(shù)組協(xié)變會破壞泛型的類型安全,所以不允許實例化泛型類型的數(shù)組(除非類型參數(shù)是未綁定的通配符,比如 List<?>)。
構(gòu)造延遲
因為可以擦除功能,所以 List<Integer> 和 List<String> 是同一個類,編譯器在編譯 List<V> 時只生成一個類(和 C++ 不同)。因此,在編譯 List<V> 類時,編譯器不知道 V 所表示的類型,所以它就不能像知道類所表示的具體類型那樣處理 List<V> 類定義中的類型參數(shù)(List<V> 中的 V)。
因為運(yùn)行時不能區(qū)分 List<String> 和 List<Integer>(運(yùn)行時都是 List),用泛型類型參數(shù)標(biāo)識類型的變量的構(gòu)造就成了問題。運(yùn)行時缺乏類型信息,這給泛型容器類和希望創(chuàng)建保護(hù)性副本的泛型類提出了難題。
比如泛型類 Foo:
class Foo<T> {
public void doSomething(T param) { ... }
}
在這里可以看到一種模式 —— 與泛型有關(guān)的很多問題或者折衷并非來自泛型本身,而是保持和已有代碼兼容的要求帶來的副作用。
泛化已有的類
在轉(zhuǎn)化現(xiàn)有的庫類來使用泛型方面沒有多少技巧,但與平常的情況相同,向后兼容性不會憑空而來。我已經(jīng)討論了兩個例子,其中向后兼容性限制了類庫的泛化。
另一種不同的泛化方法可能不存在向后兼容問題,這就是 Collections.toArray nike shox r4(Object[])。傳入 toArray() 的數(shù)組有兩個目的 —— 如果集合足夠小,那么可以將其內(nèi)容直接放在提供的數(shù)組中。否則,利用反射(reflection)創(chuàng)建相同類型的新數(shù)組來接受結(jié)果。如果從頭開始重寫 Collections 框架,那么很可能傳遞給 Collections.toArray() 的參數(shù)不是一個數(shù)組,而是一個類文字:
interface Collection<E> {
public T[] toArray(Class<T super E> elementClass);
}
因為 Collections 框架作為良好類設(shè)計的例子被廣泛效仿,但是它的設(shè)計受到向后兼容性約束,所以這些地方值得您注意,不要盲目效仿。
首先,常常被混淆的泛型 Collections API 的一個重要方面是 containsAll()、removeAll() 和 retainAll() 的簽名。您可能認(rèn)為 remove() 和 removeAll() 的簽名應(yīng)該是:
interface Collection<E> {
public boolean remove(E e); // not really
public void removeAll(Collection<? extends E> c); // not really
}
但實際上卻是:
interface Collection<E> {
public boolean remove(Object o);
public void removeAll(Collection<?> c);
}
為什么呢?答案同樣是因為向后兼容性。x.remove(o) 的接口表明“如果 o 包含在 x 中,則刪除它,否則什么也不做。”如果 x 是一個泛型集合,那么 o 不一定與 x 的類型參數(shù)兼容。如果 removeAll() 被泛化為只有類型兼容時才能調(diào)用(Collection<? extends E>),那么在泛化之前,合法的代碼序列就會變得不合法,比如:
// a collection of Integers
Collection c = new HashSet();
// a collection of Objects
Collection r = new HashSet();
c.removeAll(r);
如果上述片段用直觀的方法泛化(將 c 設(shè)為 Collection<Integer>,r 設(shè)為 Collection<Object>),如果 removeAll() 的簽名要求其參數(shù)為 Collection<? extends E> 而不是 no-op,那么就無法編譯上面的代碼。泛型類庫的一個主要目標(biāo)就是不打破或者改變已有代碼的語義,因此,必須用比從頭重新設(shè)計泛型所使用類型約束更弱的類型約束來定義 remove()、removeAll()、retainAll() 和 containsAll()。
在泛型之前設(shè)計的類可能阻礙了“顯然的”泛型化方法。這種情況下就要像上例這樣進(jìn)行折衷,但是如果從頭設(shè)計新的泛型類,理解 Java 類庫中的哪些東西是向后兼容的結(jié)果很有意義,這樣可以避免不適當(dāng)?shù)哪7隆?/p>
擦除的實現(xiàn)
因為泛型基本上都是在 Java 編譯器中而不是運(yùn)行庫中實現(xiàn)的,所以在生成字節(jié)碼的時候,差不多所有關(guān)于泛型類型的類型信息都被“擦掉”了。換句話說,編譯器生成的代碼與您手工編寫的不用泛型、檢查程序的類型安全后進(jìn)行強(qiáng)制類型轉(zhuǎn)換所得到的代碼基本相同。與 C++ 不同,List<Integer> 和 List<String> 是同一個類(雖然是不同的類型但都是 List<?> 的子類型,與以前的版本相比,在 JDK 5.0 中這是一個更重要的區(qū)別)。
擦除意味著一個類不能同時實現(xiàn) Comparable<String> 和 Comparable<Number>,因為事實上兩者都在同一個接口中,指定同一個 compareTo() 方法。聲明 DecimalString 類以便與 String 與 Number 比較似乎是明智的,但對于 Java 編譯器來說,這相當(dāng)于對同一個方法進(jìn)行了兩次聲明:
public class DecimalString implements Comparable fashion cap<Number>, Comparable<String> { ... } // nope
擦除的另一個后果是,對泛型類型參數(shù)是用強(qiáng)制類型轉(zhuǎn)換或者 instanceof 毫無意義。下面的代碼完全不會改善代碼的類型安全性:
public <T> T naiveCast(T t, Object o) { return (T) o; }
編譯器僅僅發(fā)出一個類型未檢查轉(zhuǎn)換警告,因為它不知道這種轉(zhuǎn)換是否安全。naiveCast() 方法實際上根本不作任何轉(zhuǎn)換,T 直接被替換為 Object,與期望的相反,傳入的對象被強(qiáng)制轉(zhuǎn)換為 Object。
擦除也是造成上述構(gòu)造問題的原因,即不能創(chuàng)建泛型類型的對象,因為編譯器不知道要調(diào)用什么構(gòu)造函數(shù)。如果泛型類需要構(gòu)造用泛型類型參數(shù)來指定類型的對象,那么構(gòu)造函數(shù)應(yīng)該接受類文字(Foo.class)并將它們保存起來,以便通過反射創(chuàng)建實例。
結(jié)束語
泛型是 Java 語言走向類型安全的一大步,但是泛型設(shè)施的設(shè)計和類庫的泛化并非未經(jīng)過妥協(xié)。擴(kuò)展虛擬機(jī)指令集來支持泛型被認(rèn)為是無法接受的,因為這會為 Java 廠商升級其 JVM 造成難以逾越的障礙。因此采用了可以完全在編譯器中實現(xiàn)的擦除方法。類似地,在泛型 Java 類庫時,保持向后兼容也為類庫的泛化方式設(shè)置了很多限制,產(chǎn)生了一些混亂的、令人沮喪的結(jié)構(gòu)(如 Array.newInstance())。這并非泛型本身的問題,而是與語言的演化與兼容有關(guān)。但這些也使得泛型學(xué)習(xí)和應(yīng)用起來更讓人迷惑,更加困難。
2009年12月5日
#
在Web2.0的浪潮中,各種頁面技術(shù)和框架不斷涌現(xiàn),為服務(wù)器端的基礎(chǔ)架構(gòu)提出了更高的穩(wěn)定性和可擴(kuò)展性的要求。近年來,作為開源中間件的全球領(lǐng)導(dǎo)者,JBoss在J2EE應(yīng)用服務(wù)器領(lǐng)域已成為發(fā)展最為迅速的應(yīng)用服務(wù)器。在市場占有率和服務(wù)滿意度上取得了巨大的成功,絲毫不遜色于其它的非開源競爭對手,如WebSphere、WebLogic、Application Server。JBoss Web的諸多優(yōu)越性能,正是其廣為流行的原因。
基于Tomcat內(nèi)核,青勝于藍(lán)
Tomcat 服務(wù)器是一個免費(fèi)的開放源代碼的Web 應(yīng)用服務(wù)器,技術(shù)先進(jìn)、性能穩(wěn)定,而且免費(fèi),因而深受Java 愛好者的喜愛并得到了部分軟件開發(fā)商的認(rèn)可。其運(yùn)行時占用的系統(tǒng)資源小,擴(kuò)展性好,且支持負(fù)載平衡與郵件服務(wù)等開發(fā)應(yīng)用系統(tǒng)常用的功能。作為一個小型的輕量級應(yīng)用服務(wù)器,Tomcat在中小型系統(tǒng)和并發(fā)訪問用戶不是很多的場合下被普遍使用,成為目前比較流行的Web 應(yīng)用服務(wù)器。
而JBoss Web采用業(yè)界最優(yōu)的開源Java Web引擎, 將Java社區(qū)中下載量最大,用戶數(shù)最多,標(biāo)準(zhǔn)支持最完備的Tomcat內(nèi)核作為其Servlet容器引擎,并加以審核和調(diào)優(yōu)。單純的Tomcat性能有限,在很多地方表現(xiàn)有欠缺,如活動連接支持、靜態(tài)內(nèi)容、大文件和HTTPS等。除了性能問題,Tomcat的另一大缺點是它是一個受限的集成平臺,僅能運(yùn)行Java應(yīng)用程序。企業(yè)在使用時Tomcat,往往還需同時部署Apache Web Server以與之整合。此配置較為繁瑣,且不能保證性能的優(yōu)越性。
JBoss在Tomcat的基礎(chǔ)上,對其進(jìn)行本地化,將Tomcat 以內(nèi)嵌的方式集成到 JBoss 中。JBoss Web通過使用APR和Tomcat本地技術(shù)的混合模型來解決Tomcat的諸多不足。混合技術(shù)模型從最新的操作系統(tǒng)技術(shù)里提供了最好的線程和事件處理。結(jié)果,JBoss Web達(dá)到了可擴(kuò)展性,性能參數(shù)匹配甚至超越了本地Apache HTTP服務(wù)器或者IIS。譬如JBoss Web能夠提供數(shù)據(jù)庫連接池服務(wù),不僅支持 JSP 等 Java 技術(shù),同時還支持其他 Web 技術(shù)的集成,譬如 PHP、.NET 兩大陣營。
標(biāo)準(zhǔn)化是減小技術(shù)依賴風(fēng)險,保護(hù)投資最好的方式。JBoss Web率先支持全系列JEE Web標(biāo)準(zhǔn),從根本上保證了應(yīng)用“一次開發(fā),到處運(yùn)行”的特點,使應(yīng)用成品能方便地在JBoss Web和其他Java Web服務(wù)器之間輕易遷移。
集多功能于一身,性能卓越
作為Web 應(yīng)用服務(wù)器中的明星產(chǎn)品,JBoss Web服務(wù)器集多種功能于一身。其關(guān)鍵功能包括:完全支持Java EE、高度的擴(kuò)展性、快速的靜態(tài)內(nèi)容處理、群集、OpenSSL、URL重寫和綜合性。
JBoss Web服務(wù)器具有原生特性和強(qiáng)大的可擴(kuò)展性,可支持多種并非基于Java的服務(wù)器內(nèi)容處理技術(shù),可同時運(yùn)行JSP, Servlet, Microsoft .NET , PHP 及 CGI,為其提供一個單一的、高性能的企業(yè)級部署平臺。
與Tomcat 相比,JBoss Web在靜態(tài)資源訪問方面性能優(yōu)越。JBoss Web支持兩種組件模式——純Java和Native I/O。在Native組件的支持下,動態(tài)運(yùn)行不會受到任何影響,而靜態(tài)資源的訪問利用了操作系統(tǒng)本身提供的0拷貝傳送,CPU消耗降低,響應(yīng)時間縮短,吞吐率大大提高,混合的連接模式支持最大達(dá)到10000個并發(fā)客戶端的同時訪問,與Apache Web服務(wù)器相當(dāng)。部署于高性能的操作系統(tǒng),可利用JBoss Web對純Java和Native I/O兩種模式的支持,使得應(yīng)用在開發(fā)時可隨時跨平臺敏捷遷移,而部署于高性能的操作系統(tǒng)相關(guān)的Native環(huán)境。由于JBoss Web較好地解決了靜態(tài)資源的訪問性能問題,可在解決方案中把它直接作為強(qiáng)大的LVS的分發(fā)對象,和RHEL負(fù)載均衡系統(tǒng)結(jié)合,形成理論上無限線性擴(kuò)展的負(fù)載均衡場景。
OpenSSL是業(yè)界最為快速和安全的開源傳輸組件,可借助操作系統(tǒng)和硬件的特性實現(xiàn)高效的安全承載。JBoss Web集成了OpenSSL,可提供高效的安全傳輸服務(wù),使得安全機(jī)制更上臺階。研究表明, JBoss Web中的SSL性能比單純的Tomcat快四倍。
URL重寫功能可縮短URL,隱藏實際路徑提高安全性,易于用戶記憶和鍵入,及被搜索引擎收錄。Tomcat 不具備URL重寫功能,JBoss Web則可提供一個靈活的URL rewriting操作引擎,支持無限個規(guī)則數(shù)和規(guī)則條件。URL可被重寫以支持遺留的URL錯誤處理,或應(yīng)對服務(wù)器不時產(chǎn)生的其他問題。
JBoss Web既可單獨運(yùn)行,也可無縫嵌入JBoss應(yīng)用服務(wù)器,成為JBoss中間件平臺的一部分。不僅后臺服務(wù)調(diào)用的性能將得以提升,也可利用以下JBoss平臺的特性提升Web應(yīng)用功能:
基于JGroups的多種集群方案的支持
基于Arjuna技術(shù)的JTA和JTS的事務(wù)處理支持
優(yōu)化的線程池和連接池的支持
基于JMX 控制臺的基本管理支持和JBoss On的高級管理維護(hù)支持
基于JBoss AOP技術(shù)的面向方面架構(gòu)的支持
Hibernate服務(wù)組件的支持
專業(yè)團(tuán)隊支持
業(yè)界大多數(shù)開源產(chǎn)品在技術(shù)方面富于創(chuàng)新性,但在可持續(xù)性,產(chǎn)品生命周期規(guī)劃,以及質(zhì)量保證方面缺乏有效保障,為軟件集成商和最終用戶所詬病。紅帽所力行的“專業(yè)化開源技術(shù)”則完美解決了這一問題。
來自開源社區(qū)的JBoss Web,在紅帽專業(yè)化開源的錘煉下,在性能、擴(kuò)展性、穩(wěn)定性、安全性等方面,已成為一個達(dá)到企業(yè)級,甚至電信級標(biāo)準(zhǔn)的優(yōu)秀產(chǎn)品。紅帽不僅有專職的技術(shù)團(tuán)隊投入JBoss Web的開發(fā),而且具備專門的QA團(tuán)隊為產(chǎn)品作質(zhì)量保證。完善的集成測試和兼容性測試保證了JBoss Web自身的穩(wěn)定性,并保證了它的后向兼容和其他JBoss產(chǎn)品協(xié)作良好的互操作性。
在服務(wù)體系保障方面,JBoss 開拓了以產(chǎn)品專家提供的專家級支持服務(wù)作為開源軟件強(qiáng)大后盾的軟件生態(tài)模式。公司以及龐大的 JBoss 授權(quán)服務(wù)合作伙伴網(wǎng)絡(luò)可為包括JBoss Web在內(nèi)的整個JEMS 產(chǎn)品套件提供全面的支持服務(wù)。與Tomcat相比,JBoss Web 可提供遷移服務(wù)與現(xiàn)場專家服務(wù),在遷移服務(wù)方面,專家指導(dǎo)應(yīng)用可從Tomcat向JBoss Web遷移,省時省力。獨特的服務(wù)訂閱模式,全力保障軟件生命周期,讓企業(yè)高枕無憂。