(轉(zhuǎn))Java 5.0多線程編程(2)
*1:
定義了幾個(gè)任務(wù)
*2:
初始了任務(wù)執(zhí)行工具。任務(wù)的執(zhí)行框架將會(huì)在后面解釋。
*3:
執(zhí)行任務(wù),任務(wù)啟動(dòng)時(shí)返回了一個(gè)
Future
對(duì)象,如果想得到任務(wù)執(zhí)行的結(jié)果或者是異常可對(duì)這個(gè)
Future
對(duì)象進(jìn)行操作。
Future
所含的值必須跟
Callable
所含的值對(duì)映,比如說(shuō)例子中
Future
*4:
任務(wù)
1
正常執(zhí)行完畢,
future1.get()
會(huì)返回線程的值
*5:
任務(wù)
2
在進(jìn)行一個(gè)死循環(huán),調(diào)用
future2.cancel(true)
來(lái)中止此線程。傳入的參數(shù)標(biāo)明是否可打斷線程,
true
表明可以打斷。
*6:
任務(wù)
3
拋出異常,調(diào)用
future3.get()
時(shí)會(huì)引起異常的拋出。
?
運(yùn)行
Executor
會(huì)有以下運(yùn)行結(jié)果:
looping....
Task done. //*1
looping....
looping....//*2
looping....
looping....
looping....
looping....
Thread 2 terminated? :true //*3
//*4
java.util.concurrent.ExecutionException: java.lang.Exception: Callable terminated with Exception!
??????? at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:205)
??????? at java.util.concurrent.FutureTask.get(FutureTask.java:80)
??????? at concurrent.Executor.main(Executor.java:43)
??????? ……. |
*1:
任務(wù)
1
正常結(jié)束
*2:
任務(wù)
2
是個(gè)死循環(huán),這是它的打印結(jié)果
*3:
指示任務(wù)
2
被取消
*4:
在執(zhí)行
future3.get()
時(shí)得到任務(wù)
3
拋出的異常
3:新的任務(wù)執(zhí)行架構(gòu)
?? 在
Java 5.0
之前啟動(dòng)一個(gè)任務(wù)是通過(guò)調(diào)用
Thread
類(lèi)的
start()
方法來(lái)實(shí)現(xiàn)的,任務(wù)的提于交和執(zhí)行是同時(shí)進(jìn)行的,如果你想對(duì)任務(wù)的執(zhí)行進(jìn)行調(diào)度或是控制同時(shí)執(zhí)行的線程數(shù)量就需要額外編寫(xiě)代碼來(lái)完成。
5.0
里提供了一個(gè)新的任務(wù)執(zhí)行架構(gòu)使你可以輕松地調(diào)度和控制任務(wù)的執(zhí)行,并且可以建立一個(gè)類(lèi)似數(shù)據(jù)庫(kù)連接池的線程池來(lái)執(zhí)行任務(wù)。這個(gè)架構(gòu)主要有三個(gè)接口和其相應(yīng)的具體類(lèi)組成。這三個(gè)接口是
Executor, ExecutorService
和
ScheduledExecutorService
,讓我們先用一個(gè)圖來(lái)顯示它們的關(guān)系:
?
? 圖的左側(cè)是接口,圖的右側(cè)是這些接口的具體類(lèi)。注意
Executor
是沒(méi)有直接具體實(shí)現(xiàn)的。
Executor
接口:
是用來(lái)執(zhí)行
Runnable
任務(wù)的,它只定義一個(gè)方法:
-
execute(Runnable command)
:執(zhí)行
Ruannable
類(lèi)型的任務(wù)
ExecutorService
接口:
ExecutorService
繼承了
Executor
的方法,并提供了執(zhí)行
Callable
任務(wù)和中止任務(wù)執(zhí)行的服務(wù),其定義的方法主要有:
-
submit(task)
:可用來(lái)提交
Callable
或
Runnable
任務(wù),并返回代表此任務(wù)的
Future
對(duì)象
-
invokeAll(collection of tasks)
:批處理任務(wù)集合,并返回一個(gè)代表這些任務(wù)的
Future
對(duì)象集合
-
shutdown()
:在完成已提交的任務(wù)后關(guān)閉服務(wù),不再接受新任務(wù)
-
shutdownNow()
:停止所有正在執(zhí)行的任務(wù)并關(guān)閉服務(wù)。
-
isTerminated()
:測(cè)試是否所有任務(wù)都執(zhí)行完畢了。
-
isShutdown()
:測(cè)試是否該
ExecutorService
已被關(guān)閉
ScheduledExecutorService
接口
在
ExecutorService
的基礎(chǔ)上,
ScheduledExecutorService
提供了按時(shí)間安排執(zhí)行任務(wù)的功能,它提供的方法主要有:
-
schedule(task, initDelay):
安排所提交的
Callable
或
Runnable
任務(wù)在
initDelay
指定的時(shí)間后執(zhí)行。
-
scheduleAtFixedRate()
:安排所提交的
Runnable
任務(wù)按指定的間隔重復(fù)執(zhí)行
-
scheduleWithFixedDelay()
:安排所提交的
Runnable
任務(wù)在每次執(zhí)行完后,等待
delay
所指定的時(shí)間后重復(fù)執(zhí)行。
代碼:
ScheduleExecutorService
的例子
public class ScheduledExecutorServiceTest {
??????? public static void main(String[] args)
?????????????? throws InterruptedException, ExecutionException{
?????????????? //*1
??????????????? ScheduledExecutorService service = Executors.newScheduledThreadPool(2);
??????????????? //*2
??????????????? Runnable task1 = new Runnable() {
???????????????????? public void run() {
??????????????????????? System.out.println("Task repeating.");
???????????????????? }
??????????????? };
??????????????? //*3
??????????????? final ScheduledFuture future1 =
??????????????????????? service.scheduleAtFixedRate(task1, 0, 1, TimeUnit.SECONDS);
??????????????? //*4
??????????????? ScheduledFuture
???????????????????? public String call(){
???????????????????????????? future1.cancel(true);
???????????????????????????? return "task cancelled!";
???????????????
?????}
??????????????? }, 5, TimeUnit.SECONDS);
??????????????? System.out.println(future2.get());
//*5
service.shutdown();
??????? }
} |
?? 這個(gè)例子有兩個(gè)任務(wù),第一個(gè)任務(wù)每隔一秒打印一句“
Task repeating
”
,
第二個(gè)任務(wù)在
5
秒鐘后取消第一個(gè)任務(wù)。
*1:
初始化一個(gè)
ScheduledExecutorService
對(duì)象,這個(gè)對(duì)象的線程池大小為
2
。
*2:
用內(nèi)函數(shù)的方式定義了一個(gè)
Runnable
任務(wù)。
*3:
調(diào)用所定義的
ScheduledExecutorService
對(duì)象來(lái)執(zhí)行任務(wù),任務(wù)每秒執(zhí)行一次。能重復(fù)執(zhí)行的任務(wù)一定是
Runnable
類(lèi)型。注意我們可以用
TimeUnit
來(lái)制定時(shí)間單位,這也是
Java 5.0
里新的特征,
5.0
以前的記時(shí)單位是微秒,現(xiàn)在可精確到奈秒。
*4:
調(diào)用
ScheduledExecutorService
對(duì)象來(lái)執(zhí)行第二個(gè)任務(wù),第二個(gè)任務(wù)所作的就是在
5
秒鐘后取消第一個(gè)任務(wù)。
*5:
關(guān)閉服務(wù)。
Executors
類(lèi)
?? 雖然以上提到的接口有其實(shí)現(xiàn)的具體類(lèi),但為了方便
Java 5.0
建議使用
Executors
的工具類(lèi)來(lái)得到
Executor
接口的具體對(duì)象,需要注意的是
Executors
是一個(gè)類(lèi),不是
Executor
的復(fù)數(shù)形式。
Executors
提供了以下一些
static
的方法:
-
callable(Runnable task):
將
Runnable
的任務(wù)轉(zhuǎn)化成
Callable
的任務(wù)
-
newSingleThreadExecutor:
產(chǎn)生一個(gè)
ExecutorService
對(duì)象,這個(gè)對(duì)象只有一個(gè)線程可用來(lái)執(zhí)行任務(wù),若任務(wù)多于一個(gè),任務(wù)將按先后順序執(zhí)行。
-
newCachedThreadPool():
產(chǎn)生一個(gè)
ExecutorService
對(duì)象,這個(gè)對(duì)象帶有一個(gè)線程池,線程池的大小會(huì)根據(jù)需要調(diào)整,線程執(zhí)行完任務(wù)后返回線程池,供執(zhí)行下一次任務(wù)使用。
-
newFixedThreadPool(int poolSize)
:產(chǎn)生一個(gè)
ExecutorService
對(duì)象,這個(gè)對(duì)象帶有一個(gè)大小為
poolSize
的線程池,若任務(wù)數(shù)量大于
poolSize
,任務(wù)會(huì)被放在一個(gè)
queue
里順序執(zhí)行。
-
newSingleThreadScheduledExecutor
:產(chǎn)生一個(gè)
ScheduledExecutorService
對(duì)象,這個(gè)對(duì)象的線程池大小為
1
,若任務(wù)多于一個(gè),任務(wù)將按先后順序執(zhí)行。
-
newScheduledThreadPool(int poolSize):
產(chǎn)生一個(gè)
ScheduledExecutorService
對(duì)象,這個(gè)對(duì)象的線程池大小為
poolSize
,若任務(wù)數(shù)量大于
poolSize
,任務(wù)會(huì)在一個(gè)
queue
里等待執(zhí)行
以下是得到和使用
ExecutorService
的例子:
代碼:如何調(diào)用
Executors
來(lái)獲得各種服務(wù)對(duì)象
//Single Threaded ExecutorService ???? ExecutorService singleThreadeService = Executors.newSingleThreadExecutor();
//Cached ExecutorService
???? ExecutorService cachedService = Executors.newCachedThreadPool();
//Fixed number of ExecutorService
???? ExecutorService fixedService = Executors.newFixedThreadPool(3);
//Single ScheduledExecutorService
???? ScheduledExecutorService singleScheduledService =
????????? Executors.newSingleThreadScheduledExecutor();
//Fixed number of ScheduledExecutorService
ScheduledExecutorService fixedScheduledService =
???? Executors.newScheduledThreadPool(3); |
4:Lockers和Condition接口
?? 在多線程編程里面一個(gè)重要的概念是鎖定,如果一個(gè)資源是多個(gè)線程共享的,為了保證數(shù)據(jù)的完整性,在進(jìn)行事務(wù)性操作時(shí)需要將共享資源鎖定,這樣可以保證在做事務(wù)性操作時(shí)只有一個(gè)線程能對(duì)資源進(jìn)行操作,從而保證數(shù)據(jù)的完整性。在
5.0
以前,鎖定的功能是由
Synchronized
關(guān)鍵字來(lái)實(shí)現(xiàn)的,這樣做存在幾個(gè)問(wèn)題:
-
每次只能對(duì)一個(gè)對(duì)象進(jìn)行鎖定。若需要鎖定多個(gè)對(duì)象,編程就比較麻煩,一不小心就會(huì)出現(xiàn)死鎖現(xiàn)象。
-
如果線程因拿不到鎖定而進(jìn)入等待狀況,是沒(méi)有辦法將其打斷的
在 Java 5.0 里出現(xiàn)兩種鎖的工具可供使用,下圖是這兩個(gè)工具的接口及其實(shí)現(xiàn):
posted on 2007-03-26 14:30 advincenting 閱讀(473) 評(píng)論(0) 編輯 收藏