国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

論線程池的線程粒度劃分與深淺放置

2019-11-15 00:57:45
字體:
供稿:網(wǎng)友
論線程池的線程粒度劃分與深淺放置

摘要:多線程任務(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é)果的返回值”。
  1. 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;}}

上面這段代碼不僅用到了多線程取結(jié)果值的方法,還有另外的功能:在執(zhí)行某一項job時,若其發(fā)生了異常,則會連帶關(guān)閉其他運行在此線程池上的所有線程。這有時是很有用的。到目前為止,以上討論的還停留在線程池的使用方法上。然而,現(xiàn)在的問題不是如何使用線程池,那太low了不是。當(dāng)前的問題是,如何控制job的深淺,如何決定job的深淺。當(dāng)你有很多任務(wù)要放在線程池中時,他們可能有各種不同的組織形式,相對的也就有不同的實現(xiàn)辦法。例如:1、線程們可以按天來劃分,每天起一個線程,多少天就起多少個線程丟在里面;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í)行完畢的代碼段。
  1. 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!");

可以看到,把所有的job都提交完后,就要起個while循環(huán)來監(jiān)聽這個線程池,每隔一秒去問一下所有的線程是不是都跑完了。在得到肯定的答復(fù)后,就可以說,"angel wang 做完了所有的工作, Good job!"了。綜上所述,創(chuàng)建線程池的位置很重要,它直接決定了劃分線程的粒度,而線程的粒度是需要你來把控的。PS:java.sql.Connection是非線程安全的,各線程間不能對同一個Connection實例進行操作,不然對數(shù)據(jù)庫的操作會亂掉。但也要注意,如果需要啟動多線程對同一個數(shù)據(jù)庫進行操作,每個線程要使用其自身創(chuàng)建的Connection實例來連接并操作數(shù)據(jù)庫,如果不加限制的話,那么對該數(shù)據(jù)庫建立的連接數(shù)會過多,導(dǎo)致建立連接不成功。因此,要么在數(shù)據(jù)庫連接池中配置最多可以創(chuàng)建的連接數(shù),要么控制創(chuàng)建出的線程個數(shù),進行連接池配置要方便及容易許多。這也是數(shù)據(jù)庫連接池如:Druid、DBCP、C3P0存在的意義之一。最近換了城市,換了份工作,進入互聯(lián)網(wǎng)公司,遇到了很多之前沒有遇到過的問題,技術(shù)上的、管理上的、溝通上的......。體會下來,真是家家有本難念的經(jīng)啊,無限燒腦中。但是兵來將擋水來土掩嘛,有什么問題解決什么問題。

來自王安琪


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 浙江省| 大余县| 修武县| 忻城县| 花垣县| 蒲江县| 三台县| 平凉市| 灵丘县| 灵丘县| 黎平县| 凉城县| 仙居县| 公安县| 杨浦区| 闻喜县| 邢台县| 句容市| 昂仁县| 积石山| 和田市| 望谟县| 邛崃市| 岳池县| 敖汉旗| 临沧市| 台前县| 华容县| 屏山县| 鄯善县| 济宁市| 新龙县| 廊坊市| 宁河县| 开原市| 南投市| 沭阳县| 色达县| 阳泉市| 南阳市| 瓮安县|