JDK5線程池亮點(diǎn)特性淺析
JDK5線程池亮點(diǎn)特性就是將Doug Lea的并發(fā)庫引入到Java標(biāo)準(zhǔn)庫中。Doug Lea確實(shí)是一個(gè)牛人,能教書,能出書,能編碼,不過這在國(guó)外還是比較普遍的,而國(guó)內(nèi)的教授們就相差太遠(yuǎn)了。
一般的服務(wù)器都需要線程池,比如Web、FTP等服務(wù)器,不過它們一般都自己實(shí)現(xiàn)了線程池,比如以前介紹過的Tomcat、Resin和Jetty等,現(xiàn)在有了JDK5,我們就沒有必要重復(fù)造車輪了,直接使用就可以,何況使用也很方便,性能也非常高。
- packageconcurrent;
- importjava.util.concurrent.ExecutorService;
- importjava.util.concurrent.Executors;
- publicclassTestThreadPool{
- publicstaticvoidmain(Stringargs[])throwsInterruptedException{
- //onlytwothreads
- ExecutorServiceexec=Executors.newFixedThreadPool(2);
- for(intindex=0;index<100;index++){
- Runnablerun=newRunnable(){
- publicvoidrun(){
- longtime=(long)(Math.random()*1000);
- System.out.println("Sleeping"+time+"ms");
- try{
- Thread.sleep(time);
- }catch(InterruptedExceptione){
- }
- }
- };
- exec.execute(run);
- }
- //mustshutdown
- exec.shutdown();
- }
- }
上面是一個(gè)簡(jiǎn)單的例子,使用了2個(gè)大小的線程池來處理100個(gè)線程。但有一個(gè)問題:在for循環(huán)的過程中,會(huì)等待線程池有空閑的線程,所以主線程會(huì)阻塞的。為了解決這個(gè)問題,一般啟動(dòng)一個(gè)線程來做for循環(huán),就是為了避免由于線程池滿了造成主線程阻塞。不過在這里我沒有這樣處理。[重要修正:經(jīng)過測(cè)試,即使線程池大小小于實(shí)際線程數(shù)大小,線程池也不會(huì)阻塞的,這與Tomcat的線程池不同,它將Runnable實(shí)例放到一個(gè)“無限”的BlockingQueue中,所以就不用一個(gè)線程啟動(dòng)for循環(huán)。
另外它使用了Executors的靜態(tài)函數(shù)生成一個(gè)固定的線程池,顧名思義,線程池的線程是不會(huì)釋放的,即使它是Idle。這就會(huì)產(chǎn)生性能問題,比如如果線程池的大小為200,當(dāng)全部使用完畢后,所有的線程會(huì)繼續(xù)留在池中,相應(yīng)的內(nèi)存和線程切換(while(true)+sleep循環(huán))都會(huì)增加。如果要避免這個(gè)問題,就必須直接使用ThreadPoolExecutor()來構(gòu)造??梢韵馮omcat的線程池一樣設(shè)置“最大線程數(shù)”、“最小線程數(shù)”和“空閑線程keepAlive的時(shí)間”。通過這些可以基本上替換Tomcat的線程池實(shí)現(xiàn)方案。
需要注意的是線程池必須使用shutdown來顯式關(guān)閉,否則主線程就無法退出。shutdown也不會(huì)阻塞主線程。
許多長(zhǎng)時(shí)間運(yùn)行的應(yīng)用有時(shí)候需要定時(shí)運(yùn)行任務(wù)完成一些諸如統(tǒng)計(jì)、優(yōu)化等工作,比如在電信行業(yè)中處理用戶話單時(shí),需要每隔1分鐘處理話單;網(wǎng)站每天凌晨統(tǒng)計(jì)用戶訪問量、用戶數(shù);大型超時(shí)凌晨3點(diǎn)統(tǒng)計(jì)當(dāng)天銷售額、以及最熱賣的商品;每周日進(jìn)行數(shù)據(jù)庫備份;公司每個(gè)月的10號(hào)計(jì)算工資并進(jìn)行轉(zhuǎn)帳等,這些都是定時(shí)任務(wù)。通過 java的并發(fā)庫concurrent可以輕松的完成這些任務(wù),而且非常的簡(jiǎn)單。
- packageconcurrent;
- importstaticjava.util.concurrent.TimeUnit.SECONDS;
- importjava.util.Date;
- importjava.util.concurrent.Executors;
- importjava.util.concurrent.ScheduledExecutorService;
- importjava.util.concurrent.ScheduledFuture;
- publicclassTestScheduledThread{
- publicstaticvoidmain(String[]args){
- finalScheduledExecutorServicescheduler=Executors
- .newScheduledThreadPool(2);
- finalRunnablebeeper=newRunnable(){
- intcount=0;
- publicvoidrun(){
- System.out.println(newDate()+"beep"+(++count));
- }
- };
- //1秒鐘后運(yùn)行,并每隔2秒運(yùn)行一次
- finalScheduledFuture<?>beeperHandle=scheduler.scheduleAtFixedRate(
- beeper,1,2,SECONDS);
- //2秒鐘后運(yùn)行,并每次在上次任務(wù)運(yùn)行完后等待5秒后重新運(yùn)行
- finalScheduledFuture<?>beeperHandle2=scheduler
- .scheduleWithFixedDelay(beeper,2,5,SECONDS);
- //30秒后結(jié)束關(guān)閉任務(wù),并且關(guān)閉Scheduler
- scheduler.schedule(newRunnable(){
- publicvoidrun(){
- beeperHandle.cancel(true);
- beeperHandle2.cancel(true);
- scheduler.shutdown();
- }
- },30,SECONDS);
- }
- }
為了退出進(jìn)程,上面的代碼中加入了關(guān)閉Scheduler的操作。而對(duì)于24小時(shí)運(yùn)行的應(yīng)用而言,是沒有必要關(guān)閉Scheduler的。
JDK5線程池亮點(diǎn)特性java.util.concurrent就向你介紹到這里,關(guān)于更多的信息我們將會(huì)陸續(xù)給你介紹。
【編輯推薦】