- 相關(guān)推薦
構建多線(xiàn)程Java應用程序
大多數服務(wù)端應用程序都需要同時(shí)處理任務(wù)的能力,這樣可以提高工作性能并增加硬件資源的利用。在早期的Java版本(1.4或更早的)中,開(kāi)發(fā)者需要完成并發(fā)(concurrent)應用程序——包括線(xiàn)程池邏輯—他們自己使用的是低層次語(yǔ)言結構和Java Thread API.但是結果卻總是不理想。Java Thread API的特性會(huì )導致不知情的編程者開(kāi)發(fā)一些難以調試的編程錯誤的代碼。
在Java5.0中,Sun公司采用了Java concurrency功能(JSR-166)來(lái)解決這些問(wèn)題,并且提供了一套標準的APIs來(lái)創(chuàng )建并開(kāi)發(fā)應用程序。本文探究了一些Java concurrency package提供的特性并使用這些功能來(lái)演示編寫(xiě)并發(fā)應用程序的技術(shù)。
Concurrent Programming的挑戰
自從它發(fā)布以來(lái),Java就提供了Thread類(lèi)和低層次語(yǔ)言結構,例如synchronized 和volatile用來(lái)開(kāi)發(fā)獨立平臺的并發(fā)應用程序。但是,用這些特性來(lái)構建并發(fā)應用程序并不是簡(jiǎn)單的事情。開(kāi)發(fā)者要面對以下的挑戰:
不正確的編程會(huì )導致一些困境,就是兩個(gè)或兩個(gè)以上的線(xiàn)程都等待永遠被鎖住的對方。
在Java語(yǔ)言中沒(méi)有機制用于寫(xiě)wait-free, lock-free算法。開(kāi)發(fā)者必須使用本地代碼。
開(kāi)發(fā)者必須編寫(xiě)他們復雜的線(xiàn)程池邏輯,這樣會(huì )很棘手并且容易出錯。
Java Concurrency Utilities的概述
JSR-166(Java concurrency utilities),是Java5.0的一部分,通過(guò)著(zhù)重在寬度并提供跨域大范圍并發(fā)編程風(fēng)格的重要功能,大大簡(jiǎn)化了在Java中并發(fā)應用程序的開(kāi)發(fā)。
Java concurrency utilities提供了多種功能,開(kāi)發(fā)者可以應用于更快更有預見(jiàn)性的并發(fā)應用程序的開(kāi)發(fā)。這些功能讓開(kāi)發(fā)者從通過(guò)寫(xiě)自定義代碼來(lái)重新發(fā)明wheel中解放出來(lái)。一些JSR-166的最顯著(zhù)的特點(diǎn)是:
標準的接口和構架來(lái)定義自定義線(xiàn)程子系統。
是一種機制用于規范調用,時(shí)序安排,執行和異步任務(wù)的控制,這是根據在Executor構架中的一套執行政策。
是一種機制通過(guò)類(lèi)用于線(xiàn)程協(xié)調,例如semaphore, mutexe, barrier, latche和 exchangers.
非阻礙FIFO列隊執行(ConcurrentLinkedQueue類(lèi))用于可升級的,有效的線(xiàn)程安全操作。
阻礙列隊執行類(lèi)來(lái)涵蓋最常見(jiàn)的使用情況,對于生成者/消費者方法,信息,并行任務(wù)和相關(guān)的并發(fā)設計。
是一種構架用于鎖定和等待不同于內置同步和監測器的條件。
隨時(shí)準備使用的類(lèi)用于在單個(gè)變量上的鎖定自由,線(xiàn)程安全的編程。
開(kāi)發(fā)一個(gè)Concurrent Java Application
本節是演示如何使用Java concurrency utility API來(lái)開(kāi)發(fā)一個(gè)多線(xiàn)程的在線(xiàn)訂單程序的電子商務(wù)應用程序。在應用程序生效并授權命令之后,把它們放在訂單處理列隊(java.util.concurrent.BlockingQueue)。訂單處理器線(xiàn)程池不斷的對訂單進(jìn)行測驗,而且當這些訂單可以使用時(shí)進(jìn)行處理。
解耦應用程序的訂單處理代碼提供了增加和減少訂單處理率的靈活性,通過(guò)改變線(xiàn)程池的大小。在一個(gè)并發(fā)BlockingQueue中放入訂單對象確保一個(gè)處理器處理一個(gè)訂單,而且它要照顧自動(dòng)同步。
在以下小節中的代碼段是截取于伴隨本文中的應用程序源代碼。
擴展ThreadPoolExecutor
Executor接口只規定了一個(gè)方法并從任務(wù)如何運行中解耦任務(wù)提交。ExecutorService子接口規定了額外的方法用于提交并追蹤異步任務(wù),以及關(guān)閉線(xiàn)程池。ThreadPoolExecutor類(lèi)是ExecutorService接口的一個(gè)具體的執行,應該足以用于大多數訂單處理應用程序的需求。
ThreadPoolExecutor也提供有用的連接方法(e.g., beforeExecute),可以覆蓋定制目的。在Listing 1中的CustomThreadPoolExecutor類(lèi)擴展了ThreadPoolExecutor類(lèi)并覆蓋了beforeExecute, afterExecute和 terminated 方法。
@Override
public void afterExecute(Runnable r, Throwable t) { super.afterExecute(r, t); Logger.log("After calling afterExecute() method for a thread " + r); } @Override public void terminated() { super.terminated(); Logger.log("Threadpool terminated"); } |
該覆蓋方法只需登陸復寫(xiě)信息,但是在現實(shí)的情況中,它們能做更有用的事情。例如,terminated方法可以發(fā)送一個(gè)在這個(gè)池中的所有線(xiàn)程都死鎖的警告。要正確構建多重覆蓋,通常你應該從在子類(lèi)中的各個(gè)方法中調用主類(lèi)的覆蓋方法。
Java concurrency API還提供了ScheduledExecutorService接口,可以擴展ExecutorServiceInterface,而且在一個(gè)特定延遲或是定期的執行之后能夠安排任務(wù)進(jìn)行運行。ScheduledExecutorThreadPool是這個(gè)接口的具體執行。確定異步任務(wù)執行
Executor 執行提交異步任務(wù),這些任務(wù)執行實(shí)際的業(yè)務(wù)邏輯。向executor提交一個(gè)任務(wù),ExecutorService接口提供重載的submit方法,可以接受Runnable 或是Callable 對象類(lèi)型。
Runnable任務(wù)類(lèi)型在以下情況下市非常有用的:
任務(wù)完成時(shí)不需要返回任何結果。
如果run()方法遇到一個(gè)例外,沒(méi)有必要拋出一個(gè)特定程序檢查例外。
移植現有的legacy 類(lèi)來(lái)實(shí)施Runnable接口是必需的。
Callable任務(wù)類(lèi)型提供了更多靈活性并提供了下列的優(yōu)點(diǎn):
任務(wù)可以返回用戶(hù)定義對象作為結果。
任務(wù)可以?huà)伋鲇脩?hù)定義的檢查例外。
你需要分別為Runnable 和Callable任務(wù)類(lèi)型執行run() 和call()方法。
在Listing 2中的OrderProcessorCallable類(lèi)執行Callable接口并指定一個(gè)Integer作為結果對象。Constructor把任務(wù)對象名稱(chēng)和BlockingQueue當做檢索命令來(lái)處理。call()方法繼續為訂單值對象調查BlockingQueue,并且處理任何所它所發(fā)現的事情。如果沒(méi)有訂單處理,call()方法會(huì )休息一段時(shí)間再繼續工作。
Call方法的無(wú)限循環(huán)在這個(gè)應用程序方案中是非常有用的,因為因為沒(méi)有必要一次又一次為每個(gè)訂單對象去創(chuàng )建并提交新的任務(wù)到ThreadPoolExecutor中。
public Integer call() throws OrderProcessingException {
while (running) { // check if current Thread is interrupted checkInterruptStatus(); // poll for OrderVO from blocking queue and do // order processing here …… } // return result return processedCount; } |
請注意異步任務(wù)執行不斷的為應用程序的生命周期運行。在大多數程序中,異步任務(wù)執行會(huì )進(jìn)行必要的操作并立即返回。
處理線(xiàn)程中斷
Call方法執行使用checkInterruptStatus方法在執行線(xiàn)程中斷上進(jìn)行經(jīng)常性檢查。這是必需的因為為了迫使任務(wù)取消,ThreadPoolExecutor會(huì )向線(xiàn)程發(fā)送一個(gè)interrupt.否則檢查中斷狀態(tài)會(huì )導致特定線(xiàn)程再也無(wú)法返回。以下的checkInterruptStatus方法檢查運行線(xiàn)程的中斷狀態(tài),如果線(xiàn)程被中斷會(huì )拋出OrderProcessingException.
private void checkInterruptStatus() throws
OrderProcessingException {
if (Thread.interrupted()) {
throw new OrderProcessingException("Thread was interrupted");
}
}
作為任務(wù)的實(shí)施,它是拋出一個(gè)異常并在運行線(xiàn)程被中斷的時(shí)候終止任務(wù)執行的一個(gè)非常好的練習。但是,基于訂單處理的應用程序需求,在這種情況下忽略線(xiàn)程中斷是非常恰當的。
【構建多線(xiàn)程Java應用程序】相關(guān)文章:
java多線(xiàn)程面試題201710-03
sun認證考試輔導:java關(guān)于多線(xiàn)程的部分操作07-27
ASP應用程序的維護方法10-21
Java與Java web的區別08-10
sun認證考試經(jīng)驗:多線(xiàn)程的幾種實(shí)現方法詳解07-24
未來(lái)郵件營(yíng)銷(xiāo)應用程序的4個(gè)爆發(fā)點(diǎn)07-26
java習題及答案10-25