JDK5線程池亮點特性淺析
JDK5線程池亮點特性就是將Doug Lea的并發庫引入到Java標準庫中。Doug Lea確實是一個牛人,能教書,能出書,能編碼,不過這在國外還是比較普遍的,而國內的教授們就相差太遠了。
一般的服務器都需要線程池,比如Web、FTP等服務器,不過它們一般都自己實現了線程池,比如以前介紹過的Tomcat、Resin和Jetty等,現在有了JDK5,我們就沒有必要重復造車輪了,直接使用就可以,何況使用也很方便,性能也非常高。
- 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();
- }
- }
上面是一個簡單的例子,使用了2個大小的線程池來處理100個線程。但有一個問題:在for循環的過程中,會等待線程池有空閑的線程,所以主線程會阻塞的。為了解決這個問題,一般啟動一個線程來做for循環,就是為了避免由于線程池滿了造成主線程阻塞。不過在這里我沒有這樣處理。[重要修正:經過測試,即使線程池大小小于實際線程數大小,線程池也不會阻塞的,這與Tomcat的線程池不同,它將Runnable實例放到一個“無限”的BlockingQueue中,所以就不用一個線程啟動for循環。
另外它使用了Executors的靜態函數生成一個固定的線程池,顧名思義,線程池的線程是不會釋放的,即使它是Idle。這就會產生性能問題,比如如果線程池的大小為200,當全部使用完畢后,所有的線程會繼續留在池中,相應的內存和線程切換(while(true)+sleep循環)都會增加。如果要避免這個問題,就必須直接使用ThreadPoolExecutor()來構造。可以像Tomcat的線程池一樣設置“最大線程數”、“最小線程數”和“空閑線程keepAlive的時間”。通過這些可以基本上替換Tomcat的線程池實現方案。
需要注意的是線程池必須使用shutdown來顯式關閉,否則主線程就無法退出。shutdown也不會阻塞主線程。
許多長時間運行的應用有時候需要定時運行任務完成一些諸如統計、優化等工作,比如在電信行業中處理用戶話單時,需要每隔1分鐘處理話單;網站每天凌晨統計用戶訪問量、用戶數;大型超時凌晨3點統計當天銷售額、以及最熱賣的商品;每周日進行數據庫備份;公司每個月的10號計算工資并進行轉帳等,這些都是定時任務。通過 java的并發庫concurrent可以輕松的完成這些任務,而且非常的簡單。
- 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秒鐘后運行,并每隔2秒運行一次
- finalScheduledFuture<?>beeperHandle=scheduler.scheduleAtFixedRate(
- beeper,1,2,SECONDS);
- //2秒鐘后運行,并每次在上次任務運行完后等待5秒后重新運行
- finalScheduledFuture<?>beeperHandle2=scheduler
- .scheduleWithFixedDelay(beeper,2,5,SECONDS);
- //30秒后結束關閉任務,并且關閉Scheduler
- scheduler.schedule(newRunnable(){
- publicvoidrun(){
- beeperHandle.cancel(true);
- beeperHandle2.cancel(true);
- scheduler.shutdown();
- }
- },30,SECONDS);
- }
- }
為了退出進程,上面的代碼中加入了關閉Scheduler的操作。而對于24小時運行的應用而言,是沒有必要關閉Scheduler的。
JDK5線程池亮點特性java.util.concurrent就向你介紹到這里,關于更多的信息我們將會陸續給你介紹。
【編輯推薦】