java线程和线程池的使用
java線程和線程池
一、創(chuàng)建多線程的方式
????java多線程非經(jīng)常見。怎樣使用多線程,怎樣創(chuàng)建線程。java中有兩種方式,第一種是讓自己的類實現(xiàn)Runnable接口。另外一種是讓自己的類繼承Thread類。事實上Thread類自己也是實現(xiàn)了Runnable接口。
詳細使用實比例如以下:
1、通過實現(xiàn)Runnable接口方式
|
2、通過繼承Thread類的方式
|
????再啟用上面創(chuàng)建的兩種線程,調(diào)運代碼例如以下:
|
????輸入結(jié)果(每次輸入可能不同)不再具體列出。對于上面的兩種方式。更推薦使用實現(xiàn)Runnable接口的方式實現(xiàn)多線程。一方面是能夠防止java單繼承的顧慮。還有一方面Runnable是面向接口編程。擴展性比起繼承Thread更好。
所以盡量使用implement Runnable的方式。
?
二、java線程類型說明
????上面是將多線程跑起來了,可是有個問題。假設(shè)不讓主線程睡眠。當(dāng)主線程(比方main線程)結(jié)束以后。假設(shè)子線程還沒結(jié)束。那么子線程是否還會執(zhí)行呢?答案是會繼續(xù)執(zhí)行,為了說明這個問題。就又涉及到j(luò)ava中線程的類型。
java中線程一共同擁有兩種類型:守護線程(daemon thread)和用戶線程(user thread)又叫非守護線程。
能夠通過thread.setDaemon()方法設(shè)置線程是否為守護線程。默認是設(shè)置非守護線程(false)。java虛擬機停止執(zhí)行的時間是虛擬機中執(zhí)行的全部線程都是守護線程的時候,也就是說假設(shè)jvm中沒有user thread的時候,jvm就停止執(zhí)行。或者說jvm在最后一個非守護線程結(jié)束的時候,將停止全部的守護進程,然后退出jvm。
????當(dāng)使用main方法開啟線程時,主線程默認是非守護進程,而用戶自己開的進程也是非守護進程。
當(dāng)主線程結(jié)束,可是子線程(默認是非守護線程)還沒結(jié)束,所以虛擬機是不停止執(zhí)行的,當(dāng)子線程執(zhí)行完以后。假設(shè)主線程也執(zhí)行完成,jvm發(fā)現(xiàn)沒有非守護線程,就將jvm關(guān)閉,所以當(dāng)main方法的主線程執(zhí)行完成以后,子線程是會繼續(xù)執(zhí)行的。
當(dāng)然我們也能夠讓在main主線程執(zhí)行完成以后,子線程不再執(zhí)行。方法就是將全部的子線程設(shè)置為守護進程setDaemon(true)就可以。
可是須要注意的是這個設(shè)置須要在線程執(zhí)行之前設(shè)置,不能在線程執(zhí)行的過程中改動線程類型。
????更直白點說假設(shè)用戶將線程設(shè)置為守護進程。那實際的意思就是告訴jvm你不用搭理我這個線程,jvm想停止的時候,不用考慮我這個線程是否運行結(jié)束。這樣的線程詳細的使用比方在垃圾回收機制的線程。就是一個守護線程。
|
?
三、線程池的使用
????上面已經(jīng)看過了能夠在代碼中直接新起線程。假設(shè)我們在主線程中新起一百個線程。讓這一百個線程同一時候工作,邏輯上是沒有不論什么問題的。可是這樣做對系統(tǒng)資源的開銷非常大,這樣會在短時間內(nèi)處理非常多的任務(wù),當(dāng)然包含新起線程等等。基于這種考慮,我們是有必要引入線程池這個東西的。線程池就是一個池子,池子里有非常多可用線程資源,假設(shè)須要就直接從這個池子里拿就是。
當(dāng)不用的時候。放入池子中,線程池會自己主動幫我們管理。所以使用線程池主要有下面兩個優(yōu)點:1、降低在創(chuàng)建和銷毀線程上所花的時間以及系統(tǒng)資源的開銷?2、如不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量線程而導(dǎo)致消耗完系統(tǒng)內(nèi)存?。
????假設(shè)我們想要使用線程池,就須要先定義這個線程池。定義線程池的時候,當(dāng)中的幾個主要參數(shù)說明例如以下:
-corePoolSize(int):線程池中保持的線程數(shù)量。包含空暇線程在內(nèi)。也就是線程池釋放的最小線程數(shù)量界限。
-maximumPoolSize(int):線程池中嫩容納最大線程數(shù)量。
-keepAliveTime(long):空暇線程保持在線程池中的時間。當(dāng)線程池中線程數(shù)量大于corePoolSize的時候。
-unit(TimeUnit枚舉類):上面參數(shù)時間的單位。能夠是分鐘。秒,毫秒等等。
-workQueue(BlockingQueue<Runnable>):任務(wù)隊列,當(dāng)線程任務(wù)提交到線程池以后,首先放入隊列中,然后線程池依照該任務(wù)隊列依次運行對應(yīng)的任務(wù)。
能夠使用的workQueue有非常多,比方:LinkedBlockingQueue等等。
-threadFactory(ThreadFactory類):新線程產(chǎn)生工廠類。
-handler(RejectedExecutionHandler類):當(dāng)提交線程拒絕運行、異常的時候。處理異常的類。
該類取值例如以下:(注意都是內(nèi)部類)
ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。 ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),可是不拋出異常。 ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù)。然后又一次嘗試運行任務(wù),反復(fù)此過程。ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)。
???除了自己定義線程池以外,?java提供了幾種經(jīng)常使用的線程池,能夠快捷的供程序猿使用,他們各自是:
1、newFixedThreadPool?創(chuàng)建固定大小數(shù)量線程池,數(shù)量通過傳入的參數(shù)決定。
2、newSingleThreadExecutor?創(chuàng)建一個線程容量的線程池,全部的線程依次運行,相當(dāng)于創(chuàng)建固定數(shù)量為1的線程池。
3、newCachedThreadPool?創(chuàng)建可緩存的線程池,沒有最大線程限制(實際上是Integer.MAX_VALUE)。假設(shè)用空暇線程等待時間超過一分鐘,就關(guān)閉該線程。
4、newScheduledThreadPool?創(chuàng)建計劃(延遲)任務(wù)線程池,線程池中的線程能夠讓其在特定的延遲時間之后運行,也能夠以固定的時間反復(fù)運行(周期性運行)。
相當(dāng)于曾經(jīng)的Timer類的使用。
5、newSingleThreadScheduledExecutor?創(chuàng)建單線程池延遲任務(wù),創(chuàng)建一個線程容量的計劃任務(wù)。
????事實上通過靜態(tài)方法創(chuàng)建的上面幾種線程池,也都是通過傳入默認的各個參數(shù)。然后返回一個有各自特點的線程池。詳細參數(shù)能夠通過查看jdk源代碼閱讀。
????有了線程池。那么我們怎樣利用線程池中線程運行我們的任務(wù),因為Java將線程池的封裝,我們拿到的線程池的線程事實上是一個包括線程任務(wù)的運行器,僅僅須要調(diào)運運行器的運行方法,就會自己主動運行我們線程中的任務(wù)。對于非計劃任務(wù),我們須要拿到一個ThreadPoolExecutor,對于計劃任務(wù)。我們須要拿到一個ScheduledThreadPoolExecutor(它是ThreadPoolExecutor的子類)。在了解這兩個類之前。須要先了解兩個接口,ExecutorService以及它的子接口ScheduleThreadExecutorService接口。上面兩個接口分別實現(xiàn)了這兩個接口,這個兩接口定義了execute(Runnable r)方法,這種方法去運行線程的任務(wù)。
也就是我們通過調(diào)運ThreadPoolExecutor或者ScheduledThreadPoolExecutor的execute(Runnable r)方法開啟我們的線程,而且運行我們的線程任務(wù),詳細代碼例如以下:
????定義一個單例的線程池:
|
????獲取線程池中的線程,而且運行線程中任務(wù):
|
?
四、計劃任務(wù)運行使用
????通過上面的樣例。也看到了計劃任務(wù)線程池的使用方式。對于計劃任務(wù),除了能夠運行普不同線程池中線程的任務(wù)以外。還能夠運行計劃任務(wù)特殊的線程要求。比方:scheduleWithFixedDelay(command, initialDelay, delay, unit);在初始化延遲之后,以特定的延遲時間反復(fù)運行。scheduleAtFixedRate(command, initialDelay, period, unit);在初始化延遲時間之后,以固定頻率反復(fù)運行。這兩種的差別是下一次運行時間延遲計算的開始時間不同,第一種是從上一次任務(wù)開始運行的時候計算。另外一種是從上一次任務(wù)運行結(jié)束的時候計算。這兩種和java之前版本號中Timer類非常相似。
可是Timer有非常多缺陷,具體的缺陷不再具體說明。而這些缺陷都能夠通過ScheduledExecutorService給完美解決。所以是時候該丟棄Timer了。
?
?
?
總結(jié)
以上是生活随笔為你收集整理的java线程和线程池的使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQLserver语句命令
- 下一篇: Codeigniter 4.0-dev