摘要:多線程任務(wù)處理對提高性能很有幫助,在java中提供的線程池也方便了對多線程任務(wù)的實現(xiàn)。使用它很簡單,而如果進行了不正確的使用,那么代碼將陷入一團亂麻。因此如何正確地使用它,如以下分享,這個技能你get到?jīng)]?
關(guān)鍵詞:多線程, 線程池, 數(shù)據(jù)庫, 算法
解決問題:如何正確使用線程池。
眾所周知,線程池在Java中非常常用,使用它也是一項最基本的技能。不過怎樣才能更合理、更方便地使用線程池,我們需要總結(jié)一下。
下面是線程池最基礎(chǔ)的使用方式。ExecutorService jobPool = Executors.newFixedThreadPool(10);while(true){Job_anqi job_anqi = new GetData_anqi();job_anqi.setParm(parm);jobPool.submit(job_anqi);}可以從以上代碼看出,產(chǎn)生了很多個job,我們不想按順序完成它們,它們之間也沒有任何的關(guān)系,因此“分布式任務(wù)”、maPReduce?現(xiàn)在還太早,步子跨太大容易扯著蛋,先把單機的多任務(wù)給完成吧。所以,我們創(chuàng)建了一個線程池,在循環(huán)中,不斷地把job填充進去,這個線程池不大,只能容納10個線程同時跑,其它的線程放進去后就得老老實實地排隊等待。當(dāng)然這里只是一個簡單的Demo,雖然它包含了“向各線程傳入?yún)?shù)”這樣?xùn)|西,更復(fù)雜的還有“在主線程中獲取各線程結(jié)果的返回值”。ExecutorService executorService =Executors.newCachedThreadPool();List<Future<String>> resultList =newArrayList<Future<String>>();// 創(chuàng)建10個任務(wù)并執(zhí)行for(int i =0; i <10; i++){// 使用ExecutorService執(zhí)行Callable類型的任務(wù),并將結(jié)果保存在future變量中Future<String> future = executorService.submit(newTaskWithResult(i));// 將任務(wù)執(zhí)行結(jié)果存儲到List中resultList.add(future);}executorService.shutdown();// 遍歷任務(wù)的結(jié)果for(Future<String> fs : resultList){try{System.out.println(fs.get());// 打印各個線程(任務(wù))執(zhí)行的結(jié)果,其中會偶爾拋出異常}catch(InterruptedException e){e.printStackTrace();}catch(ExecutionException e){executorService.shutdownNow();//某一線程發(fā)生異常時,關(guān)閉線程池e.printStackTrace();return;}}
線程們可以按天來劃分,每天起一個線程,多少天就起多少個線程丟在里面;2、
同時,線程們也可以按數(shù)據(jù)形式來劃分,每一種數(shù)據(jù)形式起一個線程,有多少種數(shù)據(jù)形式就開多少個線程;3、
再者,線程干脆按粒度來劃分,我每一千個數(shù)據(jù)批次包裝成一個線程,無論天、無論數(shù)據(jù)形式,只是每千條數(shù)據(jù)一個線程地跑;4、
甚至,你可以線程池中套線程池,每天一個線程,再在每天的數(shù)據(jù)里對每種數(shù)據(jù)形式開一個線程,再在每種數(shù)據(jù)形式里每千條數(shù)據(jù)一個線程地跑。這就有很復(fù)雜的場景了。那么該如何選擇使用哪一種劃分線程的方式呢?我們來慢慢分析。方案3是最常會想起的劃分線程池辦法,此辦法劃分的線程粒度最細,線程池放置的位置最深,也最方便。當(dāng)然從理論上來說方案3跟其他方案一樣執(zhí)行起來不會有問題,所有的任務(wù)執(zhí)行完畢后能夠與其他方案得到同樣的結(jié)果。可是,一旦我們有特殊需求時,它是不實用的。如果,你需要打印日志或者記錄程序執(zhí)行狀態(tài),比如說我要按天記錄該天任務(wù)執(zhí)行的如何,那么選擇使用方案1是非常合適的,如果性能還不行,還可以選擇使用方案4。因為在方案1和方案4中都可以知道該天的任務(wù)何時執(zhí)行完畢。若是使用方案2,則不清楚每天的任務(wù)執(zhí)行情況,因此無法實現(xiàn)記錄;使用方案3,因為它的線程池放置位置太深,更是無法實現(xiàn)按天記錄。
要實現(xiàn)記錄任務(wù)的執(zhí)行狀態(tài),那就需要對線程池進行把控,不可能將所有的任務(wù)提交到線程池中就不管了。下面是最常見的監(jiān)視線程池中所有的線程是否執(zhí)行完畢的代碼段。ExecutorService jobPool =Executors.newFixedThreadPool(10);while(true){Job_anqi job_anqi =newGetData_anqi();job_anqi.setParm(parm);jobPool.submit(job_anqi);}pool.shutdown();try{while(!jobPool.isTerminated()){Thread.sleep(1000);}}catch(InterruptedException e){e.printStackTrace();}logger.info("angel wang 做完了所有的工作, Good job!");來自王安琪
新聞熱點
疑難解答