J2SE 5.0中的java.util.concurrent程序包提供了一個(gè)新的線程框架組件,這個(gè)框架組件處理了與建立、執(zhí)行和管理線程相關(guān)的很多低層細(xì)節(jié)信息。在本文中我們將細(xì)致地了解一下它的重要特性。 如果你使用C、C++或Java先前的版本進(jìn)行多線程編程,就知道在代碼中管理線程是多么頭疼的事情。在單線程程序中,代碼中引起應(yīng)用程序失敗的bug 每次都在同一個(gè)點(diǎn)出現(xiàn)。但是在多線程程序中,只有某些原因遇到一起的時(shí)候才會(huì)出現(xiàn)失敗。由于預(yù)見(jiàn)可能引發(fā)應(yīng)用程序失敗的所有條件是非常困難的,所以多線程 編程是有挑戰(zhàn)性的。有些程序員從根本上避免這種挑戰(zhàn),而另外一些--聰明的解決問(wèn)題的人員--則一直坐在他們的計(jì)算機(jī)面前直到問(wèn)題解決。 J2SE 5.0平臺(tái)包含了一個(gè)新的并發(fā)工具程序包。這個(gè)程序包中的類替并發(fā)類(concurrent classe)或并發(fā)設(shè)計(jì)中使用的應(yīng)用程序建立阻塞(blocking)。該并發(fā)工具包含下面一些內(nèi)容: · 高性能的、靈活的線程池 · 異步執(zhí)行事務(wù)的框架組件 · 為并發(fā)訪問(wèn)優(yōu)化過(guò)的集合類宿主(host) 本文介紹了J2SE 5.0框架組件類和它們的重要特性。本文的下載代碼提供了一些簡(jiǎn)單的、容易使用的示例,它演示了所有的新線程框架組件類。你在閱讀文章內(nèi)容之后運(yùn)行這些示例可以使自己對(duì)這些特性有更好的理解。 Executor(執(zhí)行器)框架組件 Executor框架組件提供了一個(gè)簡(jiǎn)單的、標(biāo)準(zhǔn)的、可擴(kuò)充的類,它提供了一些有用的功能,如果沒(méi)有這些功能,我們要手工實(shí)現(xiàn)這些它們,會(huì)覺(jué)得十分單調(diào)和困難。該框架組件使調(diào)用、調(diào)度和執(zhí)行的操作標(biāo)準(zhǔn)化了。它通過(guò)一組執(zhí)行策略為控制異步事務(wù)提供了支持。 Executor接口執(zhí)行已提交的可以運(yùn)行的事務(wù)。它提供了一條途徑,允許我們把事務(wù)提交從事務(wù)執(zhí)行機(jī)制中分離出來(lái)。程序員通常使用Executor代替顯式地(explicitly)建立線程。Executor接口也提供事務(wù)的同步和異步執(zhí)行。 對(duì)于同步執(zhí)行,使用下面的命令: Class MySynExecutor implements Executor{ public void execute(Runnable r) { r.run(); } } 對(duì)于異步執(zhí)行,使用下面的命令: Class MyASynExecutor implements Executor{ public void execute(Runnable r) { new Thread(r).start(); } } ExecutorService(執(zhí)行器服務(wù))類 ExecutorService類為管理一個(gè)或多個(gè)異步事務(wù)的終止和跟蹤事務(wù)執(zhí)行的過(guò)程提供了方法。代碼下載中的 MyExecutorService.java文件演示了管理事務(wù)終止的過(guò)程。它初始化了大小為三個(gè)的線程池,然后依次添加了線程。當(dāng)線程的數(shù)量達(dá)到線程 池的大小限制時(shí),它調(diào)用關(guān)閉(shutdown)方法。在調(diào)用shutdown()方法之后,這個(gè)線程池不再接受新事務(wù)的執(zhí)行。在等待十秒以后,該線程池 調(diào)用shutDownNow()。這個(gè)方法會(huì)盡最大的努力來(lái)終止所有運(yùn)行中的事務(wù)。在示例中,應(yīng)用程序試圖終止運(yùn)行中的線程失敗了。 ScheduledExecutorService(調(diào)度執(zhí)行器服務(wù)) ScheduledExecutorService類是我的最喜歡的類。它對(duì)于調(diào)度那些周期性執(zhí)行的事務(wù)非常方便,而周期性執(zhí)行的事務(wù)對(duì)于清除工作(例 如清除你的應(yīng)用程序建立的臨時(shí)文件等等)尤其有用。下載代碼中的MyScheduledExecutorService.java文件通過(guò)每五秒鐘發(fā)出" 嘟嘟"一聲演示了調(diào)度的過(guò)程: final Runnable beeper = new Runnable() { public void run() { System.out.println("beep"); } }; final ScheduledFuture beeperHandle =scheduler.scheduleAtFixedRate(beeper, 1, 5, SECONDS); Future和FutureTask 在Java的早期版本中,查詢運(yùn)行中的線程狀態(tài),以及使線程在執(zhí)行之后返回一個(gè)值是非常困難的。由于run(運(yùn)行)方法返回void,你必須編寫(xiě)大量的代碼從線程中返回一個(gè)值。使用過(guò)這種方法的程序員肯定了解其痛苦的經(jīng)歷。 你可以使用Future接口或者FutureTask類從異步執(zhí)行的線程中得到一個(gè)返回值。Future接口提供了檢查計(jì)算過(guò)程是否完成、檢索計(jì)算結(jié)果 或終止計(jì)算過(guò)程的一些方法。FutureTask類提供了Future接口方法的基本實(shí)現(xiàn)(implementation)。只有計(jì)算過(guò)程完成以后才能檢 索結(jié)果;如果計(jì)算過(guò)程沒(méi)有完成,get方法會(huì)被阻塞(block)。 下載代碼中的MyStringReverser.java文件演示了FutureTask類的使用,并提供了一個(gè)容易理解的示例。它以每秒鐘一個(gè)字符的速度從后向前顯示提交的字符串,同時(shí)主線程檢測(cè)事務(wù)是否完成了: while(!future.isDone()){ System.out.println("Task not yet completed."); try{ Thread.currentThread().sleep(500); }catch(InterruptedException ie){ System.out.println("Will check after 1/2 sec."); } } 在事務(wù)完成以后,就使用get方法從Future對(duì)象中檢索結(jié)果: System.out.println("Here is result..."+future.get()); ThreadPoolExecutor(線程池執(zhí)行器) 有了ThreadPoolExecutor類之后你可以編寫(xiě)自己的服務(wù)器了。這個(gè)類為配置和調(diào)整服務(wù)器提供了很多的特性,與很多大規(guī)模的企業(yè)級(jí)EJB服務(wù)器相似。下面是它的一些配置參數(shù): · 核心和最大的線程池大小 通過(guò)把corePoolSize和maximumPoolSize設(shè)置為相同的值,你就可以建立一個(gè)大小固定的線程池了。通過(guò)把 maximumPoolSize設(shè)置為一個(gè)極大的值(例如Integer.MAX_VALUE),你就可以允許線程池容納任意數(shù)量的并發(fā)事務(wù)了。 · 根據(jù)需要構(gòu)造 在默認(rèn)情況下,只有在新事務(wù)要求的時(shí)候,ThreadPoolExecutor才開(kāi)始建立和啟動(dòng)核心的線程,但是你可以使用prestartCoreThread或prestartAllCoreThreads動(dòng)態(tài)地重載它。 · 保持活動(dòng)的時(shí)間 如果線程池中當(dāng)前線程的數(shù)量超過(guò)了corePoolSize,那么這些超過(guò)的線程的空閑時(shí)間大于keepAliveTime的時(shí)候,它們就會(huì)被終止。 · 排隊(duì) 排隊(duì)遵循下面的規(guī)則: · 如果正在運(yùn)行的線程數(shù)量少于corePoolSize,Executor總會(huì)添加新線程而不會(huì)排隊(duì)。 · 如果corePoolSize或更多數(shù)量的線程在運(yùn)行,Executor總會(huì)對(duì)請(qǐng)求進(jìn)行排隊(duì)而不會(huì)添加新線程。 · 如果某個(gè)請(qǐng)求不能參與排隊(duì),就會(huì)建立新線程,除非線程數(shù)量超過(guò)了maximumPoolSize(在超過(guò)的情況下,該事務(wù)會(huì)被拒絕)。 · Hook方法 這個(gè)類提供了beforeExecute()和afterExecute() hook方法,它們分別在每個(gè)事務(wù)執(zhí)行之前和之后被調(diào)用。為了使用它們,你必須建立這個(gè)類的子類(因?yàn)檫@些方法是受保護(hù)的)。 下載代碼中的MyThreadPoolExecutor.java提供了一些監(jiān)視多種配置參數(shù)的詳細(xì)示例。你可以發(fā)現(xiàn)隨著每個(gè)事務(wù)的增加和完成,線程池和隊(duì)列大小在不斷變化。你可以修改代碼中的設(shè)置信息。 并發(fā)集合 JDK 1.5提供了下面一些集合實(shí)現(xiàn),它們是被設(shè)計(jì)為用于多線程環(huán)境的: · ConcurrentHashMap · CopyOnWriteArrayList · CopyOnWriteArraySet ConcurrentHashMap類為檢索和更新(update)可調(diào)整的預(yù)期的并發(fā)性提供了完整的線程安全的(thread-safe)并發(fā)性支 持。CopyOnWriteArraySet是一組線程安全的變量集合,CopyOnArrayList是一個(gè)線程安全的數(shù)組列表(ArrayList) 變量。在修改原始的數(shù)組或集合之前,它們中的每一個(gè)都會(huì)把下層的數(shù)組或集合復(fù)制一份。其結(jié)果是,讀取的速度很快,而更新的速度很慢。 并發(fā)集合類為Iterator(迭代子)提供快照式的數(shù)據(jù)(即使下層數(shù)據(jù)發(fā)生了改變,在Iterator中也不會(huì)反映出來(lái))。 同步器(Synchronizer) JDK 1.5還提供了一些高級(jí)類,例如Semaphore、CountDownLatch和CyclicBarrier,還有一個(gè)用于同步的Exchanger(交換器)類。本文沒(méi)有介紹這些類的詳細(xì)的分析和使用信息,因?yàn)槔斫馑鼈冃枰恍├碚摫尘啊?br> 擁有了這些新的類之后,你可以說(shuō)服害怕多線程技術(shù)的技術(shù)上司開(kāi)發(fā)多線程應(yīng)用程序了。 Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=332695 |
|
來(lái)自: ShangShujie > 《java》