<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    神奇好望角 The Magical Cape of Good Hope

    庸人不必自擾,智者何需千慮?
    posts - 26, comments - 50, trackbacks - 0, articles - 11
      BlogJava :: 首頁 ::  :: 聯(lián)系 :: 聚合  :: 管理

    2012年1月10日

    21 世紀(jì)初,Spring 框架的誕生和崛起讓沉重而腐朽的 J2EE 遭到了當(dāng)頭棒喝,隨后大批開發(fā)人員轉(zhuǎn)投 Spring 陣營,呼吸間就讓 J2EE 陣營大傷元?dú)?。然而這種命懸一線的危機(jī)并沒有造成毀滅性的打擊,尤其是對于 Java 這種提倡開放的平臺而言,取長補(bǔ)短,互相促進(jìn)才是正道。于是,JCP 委員會痛定思痛,在 2006 年推出 Java EE 5 規(guī)范,主要是對 EJB 的開發(fā)進(jìn)行了極大幅度的簡化。2008 年發(fā)布的 Java EE 6 引入了 CDI、BV、JAX-RS 等一系列新功能,并且以配置文件(profile)的方式讓 Java EE 向輕量級邁進(jìn)了一步。特別有趣的是,Spring 框架也開始提供對某些 Java EE 注解的支持,是否標(biāo)志著兩大陣營開始合流?Java EE 7 預(yù)定于今年下半年發(fā)布,目標(biāo)是支持云計(jì)算。最近幾年來,云計(jì)算一直被炒作,卻從來沒有一個準(zhǔn)確的定義和規(guī)范,希望 Java EE 7 能夠在 Java 界扭轉(zhuǎn)這種尷尬的局面。

    下面開始詳細(xì)列舉 Java EE 7 的新功能前瞻,數(shù)據(jù)來源于《Java Magazine 2012-01/02》中的《Cloud/Java EE: Looking Ahead to Java EE 7》一文。Java EE 7 是以“日期驅(qū)動”的方式開發(fā)的,也就是說,在計(jì)劃日期到達(dá)前沒有完成的功能都將被推遲到 Java EE 8。

    Java EE 7(JSR-342)

    • 主題:讓應(yīng)用程序能夠在私有或公共云上容易地運(yùn)行。
    • 該平臺將定義一個應(yīng)用程序元數(shù)據(jù)描述符,以描述 PaaS 執(zhí)行環(huán)境(例如多租戶、資源共享、服務(wù)質(zhì)量,以及應(yīng)用程序間的依賴)。
    • 支持 HTML5、WebSocket、JSON 等新標(biāo)準(zhǔn),并為它們一一提供 API。
    • 消除受管 Bean、EJB、Servlet、JSF、CDI 和 JAX-RS 之間不一致的地方。
    • 可能在 Web 配置文件中包含 JAX-RS 2.0 和 JMS 2.0 API 修訂版。
    • 更新一些現(xiàn)有的技術(shù),可能引入用于 Java EE 的并發(fā)工具(JSR-236)和 JCache(JSR-107)。

    Java Persistence 2.1(JSR-338)

    • 支持多租戶。
    • 支持存儲過程和廠商函數(shù)。
    • 用規(guī)則(Criteria)進(jìn)行更新和刪除。
    • 支持?jǐn)?shù)據(jù)庫大綱(Scheme)的生成。
    • 持久化上下文的同步。
    • 偵聽器中的 CDI 注入。

    JAX-RS 2.0: The Java API for RESTful Web Services(JSR-339)

    • 客戶端 API——底層使用構(gòu)建者模式,可能提供上層封裝。
    • 超媒體——輕松創(chuàng)建和處理關(guān)聯(lián)了資源的鏈接。
    • 使用 Bean 驗(yàn)證框架來驗(yàn)證表單或查詢參數(shù)。
    • @Inject 更緊密集成。
    • 服務(wù)端的異步請求處理。
    • 使用“qs”進(jìn)行服務(wù)端的內(nèi)容協(xié)商。

    Java Servlet 3.1(JSR-340)

    • 為 Web 應(yīng)用程序優(yōu)化 PaaS 模型。
    • 用于安全、會話和資源的多租戶。
    • 基于 NIO2 的異步 I/O。
    • 簡化的異步 Servlet。
    • 利用 Java EE 并發(fā)工具。
    • 支持 WebSocket。

    Expression Language 3.0(JSR-341)

    • ELContext 分離為解析和求值上下文。
    • 可定制的 EL 強(qiáng)迫規(guī)則。
    • 在 EL 表達(dá)式中直接引用靜態(tài)方法和成員。
    • 添加運(yùn)算符,例如等于、字符串連接和取大小。
    • 與 CDI 集成,例如在表達(dá)式求值前/中/后生成事件。

    Java Message Service 2.0(JSR-343)

    • 簡化開發(fā)——改變 JMS 編程模型,讓應(yīng)用程序開發(fā)變得更加簡單容易。
    • 清除/澄清現(xiàn)有規(guī)范中的模糊之處。
    • 與 CDI 集成。
    • 澄清 JMS 和其他 Java EE 規(guī)范之間的關(guān)系。
    • 新的強(qiáng)制性 API允許任何 JMS 提供者能與任何 Java EE 容器集成。
    • 來自平臺的多租戶和其他云相關(guān)的功能。

    JavaServer Faces 2.2(JSR-344)

    • 簡化開發(fā)——使配置選項(xiàng)動態(tài)化,使復(fù)合組件中的 cc:interface 可選,F(xiàn)acelet 標(biāo)記庫的速記 URL,與 CDI 集成,JSF 組件的 OSGi 支持。
    • 支持 Portlet 2.0 橋(JSR-329)的實(shí)現(xiàn)。
    • 支持 HTML5 的功能,例如 HTML5 表單、元數(shù)據(jù)、頭部和區(qū)段內(nèi)容模型。
    • 流管理,頁面導(dǎo)航事件的偵聽器,以及 fileUploadBackButton 等新組件。

    Enterprise JavaBeans 3.2(JSR-345)

    • 增強(qiáng) EJB 架構(gòu)以支持 PaaS,例如多租戶。
    • 對在 EJB 外使用容器管理的事務(wù)進(jìn)行工廠化。
    • 更進(jìn)一步使用注解。
    • 與平臺中的其他規(guī)范對齊和集成。

    Contexts and Dependency Injection 1.1(JSR-346)

    • 攔截器的全局排序和管理內(nèi)建上下文的裝飾器 API。
    • 可在 Java EE 容器外啟動的嵌入式模式。
    • 聲明式地控制歸檔中的哪些包和 Bean 將被掃描。
    • 注入日志之類的靜態(tài)成員。
    • 將 Servlet 事件作為 CDI 事件發(fā)送。

    Bean Validation 1.1(JSR-349)

    • 與其他 Java EE 規(guī)范集成。
    • JAX-RS:在 HTTP 調(diào)用中驗(yàn)證參數(shù)和返回值。
    • JAXB:將約束條件轉(zhuǎn)換到 XML 模式描述符中。
    • 方法級別的驗(yàn)證。
    • 在組集合上應(yīng)用約束條件。
    • 擴(kuò)展模型以支持“與”和“或”風(fēng)格的組合。

    JCache: Java Temporary Caching API(JSR-107)

    • 在內(nèi)存中暫存 Java 對象的 API 和語義,包括對象的創(chuàng)建、共享訪問、緩存池、失效,以及跨 JVM 的一致性。

    Java State Management(JSR-350)

    • 應(yīng)用程序和 Java EE 容器可使用該 API 將狀態(tài)管理的任務(wù)交給具有不同 QoS 特征的第三方提供者。
    • 基于 Java SE 的調(diào)用者可通過查詢狀態(tài)提供者來訪問狀態(tài)數(shù)據(jù)。
    • 可添加具有不同 QoS 的提供者,API 調(diào)用者能夠按自己的規(guī)則進(jìn)行查詢。

    Batch Applications for the Java Platform(JSR-352)

    • 用于批處理應(yīng)用程序的編程模型,以及用于調(diào)度和執(zhí)行工作的運(yùn)行時。
    • 為標(biāo)準(zhǔn)編程模型定義批處理工作、批處理工作步驟、批處理應(yīng)用程序、批處理執(zhí)行器和批處理工作管理器。

    Concurrency Utilities for Java EE(JSR-236)

    • 提供一個整潔、簡單且獨(dú)立的 API,使其能用于任何 Java EE 容器中。

    Java API for JSON Processing(JSR-353)

    • 處理 JSON 的 Java API。

    posted @ 2012-02-13 22:23 蜀山兆孨龘 閱讀(5757) | 評論 (0)編輯 收藏

    ForkJoinPool 是 Java SE 7 新功能“分叉/結(jié)合框架”的核心類,現(xiàn)在可能乏人問津,但我覺得它遲早會成為主流。分叉/結(jié)合框架是一個比較特殊的線程池框架,專用于需要將一個任務(wù)不斷分解成子任務(wù)(分叉),再不斷進(jìn)行匯總得到最終結(jié)果(結(jié)合)的計(jì)算過程。比起傳統(tǒng)的線程池類 ThreadPoolExecutor,ForkJoinPool 實(shí)現(xiàn)了工作竊取算法,使得空閑線程能夠主動分擔(dān)從別的線程分解出來的子任務(wù),從而讓所有的線程都盡可能處于飽滿的工作狀態(tài),提高執(zhí)行效率。

    ForkJoinPool 提供了三類方法來調(diào)度子任務(wù):

    execute 系列
    異步執(zhí)行指定的任務(wù)。
    invokeinvokeAll
    執(zhí)行指定的任務(wù),等待完成,返回結(jié)果。
    submit 系列
    異步執(zhí)行指定的任務(wù)并立即返回一個 Future 對象。

    子任務(wù)由 ForkJoinTask 的實(shí)例來代表。它是一個抽象類,JDK 為我們提供了兩個實(shí)現(xiàn):RecursiveTaskRecursiveAction,分別用于需要和不需要返回計(jì)算結(jié)果的子任務(wù)。ForkJoinTask 提供了三個靜態(tài)的 invokeAll 方法來調(diào)度子任務(wù),注意只能在 ForkJoinPool 執(zhí)行計(jì)算的過程中調(diào)用它們。

    ForkJoinPoolForkJoinTask 還提供了很多讓人眼花繚亂的公共方法,其實(shí)它們大多數(shù)都是其內(nèi)部實(shí)現(xiàn)去調(diào)用的,對于應(yīng)用開發(fā)人員來說意義不大。

    下面以統(tǒng)計(jì) D 盤文件個數(shù)為例。這實(shí)際上是對一個文件樹的遍歷,我們需要遞歸地統(tǒng)計(jì)每個目錄下的文件數(shù)量,最后匯總,非常適合用分叉/結(jié)合框架來處理:

    // 處理單個目錄的任務(wù)
    public class CountingTask extends RecursiveTask<Integer> {
        private Path dir;
    
        public CountingTask(Path dir) {
            this.dir = dir;
        }
    
        @Override
        protected Integer compute() {
            int count = 0;
            List<CountingTask> subTasks = new ArrayList<>();
    
            // 讀取目錄 dir 的子路徑。
            try (DirectoryStream<Path> ds = Files.newDirectoryStream(dir)) {
                for (Path subPath : ds) {
                    if (Files.isDirectory(subPath, LinkOption.NOFOLLOW_LINKS)) {
                        // 對每個子目錄都新建一個子任務(wù)。
                        subTasks.add(new CountingTask(subPath));
                    } else {
                        // 遇到文件,則計(jì)數(shù)器增加 1。
                        count++;
                    }
                }
    
                if (!subTasks.isEmpty()) {
                    // 在當(dāng)前的 ForkJoinPool 上調(diào)度所有的子任務(wù)。
                    for (CountingTask subTask : invokeAll(subTasks)) {
                        count += subTask.join();
                    }
                }
            } catch (IOException ex) {
                return 0;
            }
            return count;
        }
    }
    
    // 用一個 ForkJoinPool 實(shí)例調(diào)度“總?cè)蝿?wù)”,然后敬請期待結(jié)果……
    Integer count = new ForkJoinPool().invoke(new CountingTask(Paths.get("D:/")));
        

    在我的筆記本上,經(jīng)多次運(yùn)行這段代碼,耗費(fèi)的時間穩(wěn)定在 600 豪秒左右。普通線程池(Executors.newCachedThreadPool())耗時 1100 毫秒左右,足見工作竊取的優(yōu)勢。

    結(jié)束本文前,我們來圍觀一個最神奇的結(jié)果:單線程算法(使用 Files.walkFileTree(...))比這兩個都快,平均耗時 550 毫秒!這警告我們并非引入多線程就能優(yōu)化性能,并須要先經(jīng)過多次測試才能下結(jié)論。

    posted @ 2012-02-09 10:40 蜀山兆孨龘 閱讀(2681) | 評論 (2)編輯 收藏

    前面已經(jīng)看到,Socket 類的 getInputStream()getOutStream() 方法分別獲取套接字的輸入流和輸出流。輸入流用來讀取遠(yuǎn)端發(fā)送過來的數(shù)據(jù),輸出流則用來向遠(yuǎn)端發(fā)送數(shù)據(jù)。

    輸入流

    使用套接字的輸入流讀取數(shù)據(jù)時,當(dāng)前線程會進(jìn)入阻塞狀態(tài),直到套接字收到一些數(shù)據(jù)為止(亦即套接字的接收緩沖區(qū)有可用數(shù)據(jù))。該輸入流的 available() 方法只是返回接收緩沖區(qū)的可用字節(jié)數(shù)量,不可能知道遠(yuǎn)端還要發(fā)送多少字節(jié)。使用輸入流的時候,最好先將它包裝為一個 BufferedInputStream,因?yàn)樽x取接收緩沖區(qū)將導(dǎo)致 JVM 和底層系統(tǒng)之間的切換,應(yīng)當(dāng)盡量減少切換次數(shù)以提高性能。BufferedInputStream 的緩沖區(qū)大小最好設(shè)為套接字接收緩沖區(qū)的大小。

    如果直接調(diào)用輸入流的 close() 方法來關(guān)閉它,則將導(dǎo)致套接字被關(guān)閉。對此,Socket 類提供了一個 shutdownInput() 方法來禁用輸入流。調(diào)用該方法后,每次讀操作都將返回 EOF,無法再讀取遠(yuǎn)端發(fā)送的數(shù)據(jù)。對這個 EOF 的檢測,不同的輸入流包裝體現(xiàn)出不同的結(jié)果,可能讀到 -1 個字節(jié),可能讀到的字符串為 null,還可能收到一個 EOFException 等等。禁用輸入流后,遠(yuǎn)端輸出流的行為是平臺相關(guān)的:

    • 在 BSD 平臺上,遠(yuǎn)端的發(fā)送的數(shù)據(jù)能正常接收,然后直接丟棄。遠(yuǎn)端無法知道本端的輸入流已禁用。這和 JDK 文檔描述的行為一致。
    • 在 WINSOCK 平臺上,遠(yuǎn)端發(fā)送數(shù)據(jù)將會導(dǎo)致“連接被重置”的錯誤。
    • 在 Linux 平臺上,遠(yuǎn)端發(fā)送的數(shù)據(jù)能繼續(xù)接收,直到套接字輸入緩沖區(qū)填滿,之后遠(yuǎn)端再也無法發(fā)送數(shù)據(jù)(若使用阻塞模式則進(jìn)入死鎖)。

    禁用輸入流這種技術(shù)并不常用。

    輸出流

    套接字的輸出操作實(shí)際上僅僅將數(shù)據(jù)寫到發(fā)送緩沖區(qū)內(nèi),當(dāng)發(fā)送緩沖區(qū)填滿且上次的發(fā)送成功后,由底層系統(tǒng)負(fù)責(zé)發(fā)送。如果發(fā)送緩沖區(qū)的剩余空間不夠,當(dāng)前線程就會阻塞。和輸入流類似,最好將輸出流包裝為 BufferedOutputStream。

    如果套接字的雙發(fā)都使用 ObjectInputStreamObjectOutputStream 來讀寫 Java 對象,則必須先創(chuàng)建 ObjectOutputStream,因?yàn)?ObjectInputStream 在構(gòu)造的時候會試圖讀取對象頭部,如果雙發(fā)都先創(chuàng)建 ObjectInputStream,則會互相等待對方的輸出,造成死鎖:

    // 創(chuàng)建的順序不能顛倒!
    ObjectOutputStream out = new ObjectOutputStream(socket.getOutputStream());
    ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        

    類似于輸入流,關(guān)閉輸出流也導(dǎo)致關(guān)閉套接字,所以 Socket 類同樣提供了一個 shutdownOutput() 來禁用輸出流。禁用輸出流后,已寫入發(fā)送緩沖區(qū)的數(shù)據(jù)會正常發(fā)送,之后的任何寫操作都會導(dǎo)致 IOException,且遠(yuǎn)端的輸入流始終會讀到 EOF。禁用輸出流非常有用,例如套接字的雙發(fā)都在發(fā)送完畢數(shù)據(jù)后禁用輸入流,然后雙方都會收到 EOF,從而知道數(shù)據(jù)已經(jīng)全部交換完畢,可以安全關(guān)閉套接字。直接關(guān)閉套接字會同時關(guān)閉輸入流和輸出流,且斷開連接,達(dá)不到這種效果。

    使用流的阻塞套接字的優(yōu)缺點(diǎn)

    如果要使用流進(jìn)行輸入和輸出,就只能用阻塞模式的套接字。這里總結(jié)一下阻塞套接字的優(yōu)缺點(diǎn)。先看看優(yōu)點(diǎn):

    1. 編程模型簡單,非常適合初學(xué)者上手。
    2. 以裝飾器模式設(shè)計(jì)的 Java I/O 使得開發(fā)人員可以輕松地從 I/O 流讀寫任何類型的數(shù)據(jù)。

    但在性能方面有致命的缺點(diǎn):

    1. 由于服務(wù)器套接字接受連接,以及套接字的讀寫都會阻塞,性能低下。
    2. 如果不對 I/O 流手動進(jìn)行緩沖,則可能造成一次只處理一個字節(jié),性能低下。
    3. 服務(wù)器套接字每次只能接受一個連接,導(dǎo)致 JVM 和底層系統(tǒng)之間頻繁的調(diào)用切換,性能低下。

    下一篇文章開始探討使用基于 NIO 的套接字通道和緩沖區(qū)實(shí)現(xiàn)伸縮性更強(qiáng)的 TCP 套接字。

    posted @ 2012-01-19 14:37 蜀山兆孨龘 閱讀(2276) | 評論 (1)編輯 收藏

    ServerSocket 類和 Socket 類都提供了多個公共構(gòu)造方法。不同的構(gòu)造方法不僅帶的參數(shù)不同,所具有的意義也不一樣。下面分別解析這兩個類的實(shí)例初始化過程。

    ServerSocket 實(shí)例的初始化

    ServerSocket 類提供了四個構(gòu)造器:

    public ServerSocket(int port) throws IOException
    public ServerSocket(int port, int backlog) throws IOException
    public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
    public ServerSocket() throws IOException

    帶參構(gòu)造器用來創(chuàng)建已綁定的服務(wù)器套接字,也就是說構(gòu)造成功后它就已經(jīng)開始偵聽指定的端口,且能夠調(diào)用 accept() 方法來接受客戶端連接。默認(rèn)構(gòu)造器則會創(chuàng)建未綁定的服務(wù)器套接字,構(gòu)造成功后必須手動將其綁定到一個本地地址才能用,在綁定之前可以進(jìn)行一些選項(xiàng)配置。

    帶參構(gòu)造器

    總的來說,帶參構(gòu)造器提供了三個參數(shù):

    port
    指定該服務(wù)器套接字所要偵聽的本地端口。如果為 0,則由系統(tǒng)自動分配一個端口號,這必須以另外的方式讓客戶端獲取端口號。
    backlog
    這個名詞目前還沒有合適的譯名。底層系統(tǒng)的 TCP 實(shí)現(xiàn)會維護(hù)一個連接隊(duì)列,該隊(duì)列緩存了已被 TCP 處理完畢,但還沒有被服務(wù)器套接字接受的客戶端連接。一旦某個連接被接受(通過調(diào)用 accept() 方法),它就會被從隊(duì)列中移除。backlog 參數(shù)就用于指定隊(duì)列的最大長度,默認(rèn)值為 50,但這個值只是一個建議,底層系統(tǒng)可能根據(jù)需要自動調(diào)整。如果隊(duì)列滿了,則其行為是平臺相關(guān)的:微軟的 WINSOCK 會拒絕新的連接,其他實(shí)現(xiàn)則什么都不做。嚴(yán)格地說,微軟沒有遵守規(guī)范,破壞了游戲規(guī)則……
    bindAddr
    一臺機(jī)器可能會有多個本地 IP 地址,例如同時使用多塊網(wǎng)卡。使用其他兩個帶參構(gòu)造器時,該參數(shù)為 null,服務(wù)器套接字會在所有的本地 IP 地址(0.0.0.0::0)上偵聽。如果希望只偵聽一個地址,則可使用該參數(shù)。

    默認(rèn)構(gòu)造器

    如果使用默認(rèn)構(gòu)造器,在綁定地址前,還可以做些配置。綁定操作由兩個 bind 方法定義,參數(shù)類似于帶參構(gòu)造器。配置項(xiàng)包括以下方面(都必須在綁定前配置):

    設(shè)置是否重用本地地址
    該選項(xiàng)由 setReuseAddress(boolean on) 方法配置,對應(yīng)底層系統(tǒng)的 SO_REUSEADDR 套接字選項(xiàng)。JDK 沒有定義該選項(xiàng)的默認(rèn)值。如果該選項(xiàng)為 false,則在關(guān)閉 TCP 連接時,為了保證可靠性,該連接可能在關(guān)閉后的一段時間(大約兩分鐘)內(nèi)保持超時狀態(tài)(通常稱為 TIME_WAIT 狀態(tài)或 2MSL 等待狀態(tài)),這段時間里無法將新建的服務(wù)器套接字綁定到同一個地址。在開發(fā)階段,服務(wù)器可能不斷重啟,打開改選項(xiàng)會非常有用。
    設(shè)置接收緩沖區(qū)大小
    該選項(xiàng)由 setReceiveBufferSize(int size) 方法配置,對應(yīng)底層系統(tǒng)的 SO_RCVBUF 套接字選項(xiàng),單位是字節(jié)?!禦FC 1323 - TCP Extensions for High Performance》將緩沖區(qū)大小定義為 64KB。該選項(xiàng)只是一個建議值,底層系統(tǒng)可能根據(jù)需要自行調(diào)整。
    設(shè)置超時值
    該選項(xiàng)由 setSoTimeout(int timeout) 方法配置,對應(yīng)底層系統(tǒng)的 SO_TIMEOUT 套接字選項(xiàng),單位是毫秒。默認(rèn)值為 0。該選項(xiàng)影響 accept 方法的阻塞時間長度,如果超時將引發(fā) SocketTimeoutException。如果設(shè)為 0,則表示永不超時。
    設(shè)置性能首選項(xiàng)
    性能首選項(xiàng)包括連接時間、延遲和帶寬三個選項(xiàng),由 setPerformancePreferences(int connectionTime, int latency, int bandwidth) 方法配置。這三個數(shù)值分別表示短連接時間、低延遲和高帶寬的相對重要性,數(shù)值越大則越重要;其各自的絕對值沒有意義。該方法的初衷是為了讓 Java 能在用非 TCP/IP 實(shí)現(xiàn)的套接字環(huán)境下工作得更好,某些需要對網(wǎng)絡(luò)進(jìn)行調(diào)優(yōu)的程序也可以將這三個首選項(xiàng)作為配置參數(shù)提供給用戶。

    Socket 實(shí)例的初始化

    Socket 類提供了六個公共構(gòu)造器(已過時的除外):

    public Socket(String host, int port) throws UnknownHostException, IOException
    public Socket(InetAddress address, int port) throws IOException
    public Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException
    public Socket(InetAddress address, int port, InetAddress localAddr, int localPort) throws IOException
    public Socket()
    public Socket(Proxy proxy)

    前四個構(gòu)造器創(chuàng)建已連接的客戶端套接字,也就是說構(gòu)造的時候就會去連接服務(wù)器。前兩個構(gòu)造器需要提供服務(wù)器的地址和端口作為參數(shù),本地地址和端口由系統(tǒng)自動分配;后兩個允許手動指定本地地址和端口,但極少使用。后兩個構(gòu)造器創(chuàng)建未連接的套接字,創(chuàng)建后需要調(diào)用 connect 方法手動連接,連接之前可以做一些配置。最后一個構(gòu)造器接受一個代表代理服務(wù)其的 Proxy 對象,JDK 支持 HTTP 和 SOCKS(V4 或 V5)兩種代理類型。

    連接前的配置

    在連接前,客戶端套接字不僅像服務(wù)器套接字那樣可以設(shè)置是否重用本地地址、緩沖區(qū)大小、超時值和性能首選項(xiàng),還能夠配置以下各項(xiàng)(都必須在連接前配置):

    設(shè)置是否保持活躍
    該選項(xiàng)由 setKeepAlive(boolean on) 方法配置,對應(yīng)底層系統(tǒng)的 SO_KEEPALIVE 套接字選項(xiàng)。默認(rèn)值為 false。如果打開該選項(xiàng),則套接字會定期自動發(fā)送保持活躍的探測性消息,類似于心跳檢測。根據(jù)《RFC 1122 - Requirements for Internet Hosts》的規(guī)定,保持活躍機(jī)制只是 TCP 的一個可選功能,如果支持的話,默認(rèn)必須為 false,而且這種機(jī)制默認(rèn)在成功建立連接后,且連續(xù)兩小時沒有數(shù)據(jù)傳輸?shù)那闆r下才會被激活。從另一方面來看,通過套接字的 I/O 操作完全可以知道連接是否還有效,所以該選項(xiàng)的實(shí)用價值不大。
    設(shè)置是否收發(fā)帶外數(shù)據(jù)
    該選項(xiàng)由 setOOBInline(boolean on) 方法配置,對應(yīng)底層系統(tǒng)的 SO_OOBINLINE 套接字選項(xiàng)。默認(rèn)值為 off。帶外數(shù)據(jù)(Out-of-band Data)也叫做緊急數(shù)據(jù),表示數(shù)據(jù)很重要,需要使用不同于發(fā)送普通數(shù)據(jù)的一個專用通道來發(fā)送。打開該選項(xiàng)后,就可以調(diào)用 sendUrgentData(int data) 方法發(fā)送一個字節(jié)的緊急數(shù)據(jù)。JDK 對帶外數(shù)據(jù)只提供了有限支持,緊急數(shù)據(jù)將會和普通數(shù)據(jù)一起被收到,并且無法自動區(qū)分。該選項(xiàng)對應(yīng)用開發(fā)人員意義不大。
    設(shè)置是否從容關(guān)閉連接
    該選項(xiàng)由 setSoLinger(boolean on, int linger) 方法配置,對應(yīng)底層系統(tǒng)的 SO_LINGER 套接字選項(xiàng)。默認(rèn)為 false。該選項(xiàng)只會影響套接字的關(guān)閉,其中的 linger 參數(shù)表示超時時間,單位為秒。如果打開改選項(xiàng):如果將 linger 設(shè)為 0,則關(guān)閉套接字的時候,未發(fā)送的數(shù)據(jù)會被丟棄,且另一端會出現(xiàn)連接被同位體重置的異常;如果 linger 非 0,則關(guān)閉套接字的線程將被阻塞,直到數(shù)據(jù)全部發(fā)送或超時,超時后的行為與底層系統(tǒng)相關(guān),JDK 無法控制。如果關(guān)閉該選項(xiàng),則套接字正常關(guān)閉,數(shù)據(jù)也會全部發(fā)送。由于底層實(shí)現(xiàn)的差異性,不提倡應(yīng)用開發(fā)人員打開該選項(xiàng)。
    設(shè)置是否延遲發(fā)送數(shù)據(jù)
    該選項(xiàng)由 setTcpNoDelay(boolean on) 方法配置,對應(yīng)底層系統(tǒng)的 TCP_NODELAY TCP 選項(xiàng)。默認(rèn)值為 off。打開該選項(xiàng)將禁用 Nagle 算法,TCP 包會立即發(fā)送;關(guān)閉該選項(xiàng)則會啟用 Nagle 算法,多個較小的 TCP 包會被組合成一個大包一起發(fā)送,雖然發(fā)送延遲了,但有利于避免網(wǎng)絡(luò)擁塞。默認(rèn)為 false。該選項(xiàng)對實(shí)時性很強(qiáng)的程序可能有用,但一般的程序不需要關(guān)心。
    設(shè)置流量類別
    該選項(xiàng)由 setTrafficClass(int tc) 方法配置,對應(yīng)底層系統(tǒng)的“流量類別”套接字屬性。該選項(xiàng)用于向網(wǎng)絡(luò)(例如路由器)提示從該套接字發(fā)送的包需要獲取哪些服務(wù)類型,對本地 TCP 協(xié)議棧沒有影響。IPv4 和 IPv6 分別定義了多個不同的值,例如 IPv4 將 0x08 定義為最大吞吐量,0x10 定義為最小延遲,等等??梢杂没蜻\(yùn)算將多個值合并為一個選項(xiàng)。該選項(xiàng)用來調(diào)整性能,需要根據(jù)實(shí)際情況設(shè)置。由于只是建議值,可能被網(wǎng)絡(luò)忽略。

    posted @ 2012-01-16 10:31 蜀山兆孨龘 閱讀(2300) | 評論 (2)編輯 收藏

    網(wǎng)上很多關(guān)于單例模式寫法的文章,不外乎餓漢和懶漢兩種形式的討論。很多人喜歡用懶漢式,因?yàn)橛X得它實(shí)現(xiàn)了延遲加載,可以讓系統(tǒng)的性能更好。但事實(shí)果真如此嗎?我對此存疑。

    首先我們檢查一下餓漢和懶漢單例模式最簡單的寫法(這里不討論哪種懶漢寫法更好):

    // 餓漢
    public final class HungrySingleton {
        private static final HungrySingleton INSTANCE = new HungrySingleton();
    
        private HungrySingleton() {
            System.out.println("Initializing...");
        }
    
        public static HungrySingleton getInstance() {
            return INSTANCE;
        }
    }
    
    // 懶漢
    public final class LazySingleton {
        private static LazySingleton INSTANCE;
    
        private LazySingleton() {
            System.out.println("Initializing...");
        }
    
        public static synchronized LazySingleton getInstance() {
            if (INSTANCE == null) {
                INSTANCE = new LazySingleton();
            }
            return INSTANCE;
        }
    }
        

    從理論上來說,HungrySingleton 的單例在該類第一次使用的時候創(chuàng)建,而 LazySingleton 的單例則在其 getInstance() 方法被調(diào)用的時候創(chuàng)建。至于網(wǎng)上有人聲稱“餓漢式不管用不用都會初始化”,純屬走路的時候步子邁得太大。誰的加載更遲?如果你只是調(diào)用它們的 getInstance() 方法來得到單例對象,則它們都是延遲加載,這樣懶漢式?jīng)]有任何意義,而且由于 LazySingleton 采取了同步措施,性能更低(可以說任何懶漢式的性能都低于餓漢式)。當(dāng)你使用一個單例類的時候,難道第一步不是調(diào)用 getInstance() 么?所以在自己的代碼里,我更喜歡用餓漢式。

    下面用一個例子來測試加載順序:

    // 餓漢
    System.out.println("Before");
    HungrySingleton.getInstance();
    System.out.println("After");
    
    // 懶漢
    System.out.println("Before");
    LazySingleton.getInstance();
    System.out.println("After");
        

    輸出結(jié)果都是:

    Before
    Initializing...
    After

    那么,懶漢模式還有什么存在意義?如果系統(tǒng)使用了某些需要在啟動時對類進(jìn)行掃描的框架,使用餓漢式的話,啟動時間比懶漢式更長,如果使用了大量單例類,不利于開發(fā)階段。在系統(tǒng)的正式運(yùn)行階段,所有的單例類遲早都要加載的,總的說來兩者性能持平,但是懶漢式每次都至少多一個判斷,所以越到后期越體現(xiàn)餓漢的優(yōu)越性。

    最后,推薦下《Effective Java》第二版指出的用枚舉類型實(shí)現(xiàn)的餓漢單例模式:

    // 餓漢
    public enum HungrySingleton {
        INSTANCE;
    
        private HungrySingleton() {
        }
    }
    

    這種寫法不但最簡潔,還能輕易擴(kuò)展為實(shí)例數(shù)量固定的“多例模式”。

    posted @ 2012-01-10 17:39 蜀山兆孨龘 閱讀(1847) | 評論 (6)編輯 收藏

    前面介紹了各種請求參數(shù)的注入,這些參數(shù)在 HTTP 請求中都是以純文本的方式存在的。在處理參數(shù)的時候,往往需要把這些文本參數(shù)轉(zhuǎn)換為 Java 對象。JAX-RS 提供了一些內(nèi)置的規(guī)則里自動完成這種轉(zhuǎn)換。

    轉(zhuǎn)換規(guī)則一覽

    JAX-RS 提供了四條自動類型轉(zhuǎn)換規(guī)則,下面我們逐條考察。

    原始類型

    這個早就見識過了,無需多說。舉例回顧一下:

    @GET
    @Path("{id}")
    public Movie getXxx(@PathParam("id") int id) {/*...*/}
        

    提供接受單個 String 參數(shù)的構(gòu)造器的類型

    這個也不難理解,JAX-RS 會自動調(diào)用該構(gòu)造器創(chuàng)建一個對象:

    public class Style {
        public Style(String name) {/* ... */}
        // ...
    }
    
    @GET
    @Path("{name}")
    public Movie getXxx(@PathParam("name") Style style) {
        // JAX-RS 已自動調(diào)用 xxx = new Style(name)
        // ...
    }
        

    提供靜態(tài)工廠方法 valueOf(String) 的類型

    也好理解。特別需要注意的是,所有的枚舉類型都在此列,因?yàn)榫幾g器會自動給枚舉類型加上一個這樣的工廠方法。例如:

    public enum Style {/*...*/}
    
    @GET
    @Path("{name}")
    public Movie getXxx(@PathParam("name") Style style) {
        // JAX-RS 已自動調(diào)用 style = Style.valueOf(name)
        // ...
    }
        

    類型參數(shù)滿足前兩個條件的 List<T>、Set<T>SortedSet<T>

    這條規(guī)則適用于多值參數(shù),例如查詢參數(shù):

    @GET
    @Path("xxx")
    public Movie getXxx(@QueryParam("style") Set<Style> styles) {
        // JAX-RS 已自動轉(zhuǎn)換每個 Style 對象并組裝到 Set 中
        // ...
    }
        

    轉(zhuǎn)換失敗的處理

    如果轉(zhuǎn)換失敗,JAX-RS 會根據(jù)情況自動拋出一個包裝了初始異常,但是帶不同 HTTP 錯誤碼的 WebApplicationException:對矩陣參數(shù)(@MatrixParam)、查詢參數(shù) (@QueryParam)或路徑參數(shù)(@PathParam)來說為 HTTP 404 找不到,而對頭部參數(shù)(@HeaderParam)或 Cookie 參數(shù)(@CookieParam)為 HTTP 400 錯誤請求。

    posted @ 2012-01-10 13:17 蜀山兆孨龘 閱讀(3195) | 評論 (2)編輯 收藏

    主站蜘蛛池模板: 2022年亚洲午夜一区二区福利| 亚洲AV无码不卡无码| 国产vA免费精品高清在线观看 | 成人免费午夜视频| 一本久久A久久免费精品不卡| 婷婷久久久亚洲欧洲日产国码AV| 久久久久久国产a免费观看黄色大片 | 亚洲一级免费视频| 亚洲国产av无码精品| 日韩电影免费在线观看中文字幕| 亚洲精品无码少妇30P| 国产精品无码一区二区三区免费| 久久精品国产精品亚洲蜜月| A在线观看免费网站大全| 美女视频黄a视频全免费网站一区 美女视频黄a视频全免费网站色 | 亚洲а∨精品天堂在线| 国产精品亚洲产品一区二区三区| 最近中文字幕完整版免费高清| 国产亚洲日韩一区二区三区| 免费国产在线精品一区| 亚洲精品视频在线观看视频| 婷婷亚洲天堂影院| 深夜福利在线视频免费| 亚洲精品国产肉丝袜久久| 亚洲国产激情在线一区| 亚洲日韩中文字幕在线播放| 大学生一级特黄的免费大片视频| 亚洲免费视频网站| 一区免费在线观看| 亚洲AV无码成人精品区日韩 | 亚洲免费福利视频| 情人伊人久久综合亚洲| 国产免费牲交视频| 在线观看无码AV网站永久免费| 成在人线av无码免费高潮喷水| 美女视频黄频a免费观看| 亚洲人成网站色在线观看| 亚洲视频免费在线观看| 亚洲色成人WWW永久网站| 亚洲国产V高清在线观看| 日韩精品免费电影|