Java執行緒池的認識、常用執行緒池的分析
什麼是程式,什麼是程序,什麼是執行緒,他們有什麼區別?
程式是指令和資料的有序集合,其本身並沒有任何執行的含義,是一個靜態的概念。
程序是一個動態的過程,是一個活動的實體。簡單來說,一個應用程式得到執行就可以看作是一個程序。程序可以包含多個同時執行的執行緒。程序也是擁有系統資源分配的最小基本單位。
執行緒是程序的實體,是CPU排程和分派的最小基本單位,是比執行緒更小的能獨立執行的基本單位。一個程序至少有一個執行緒。那有時候簡單的一個小程式並沒有用到執行緒,執行緒又從何而來?這裡的執行緒是由CPU呼叫資源時產生的執行緒,就是我們常說的主執行緒(姑且理解成主函式那個程式碼塊吧!)。執行緒類建立執行緒只是給了我們一個排程資源的機會,而不是說執行緒必須是我們建立,只要需要CPU排程資源就需要執行緒的建立,我們不建立,JVM自己建立(通常情況下就是這個主執行緒了)。
更深刻的瞭解可以看這裡,比喻生動形象https://www.cnblogs.com/dreamroute/p/5207813.html
什麼是執行緒池?
顧名思義,就是事先建立若干個可執行的執行緒放進一個“池(容器)”裡面,需要的時候就直接從池裡面取出來不需要自己建立,使用完畢也不需要銷燬而是放進“池”中,從而減少了建立和銷燬物件所產生的開銷。
為什麼使用(執行緒)池?
在面向物件的程式設計中,建立和銷燬物件非常耗費時間,因為建立一個物件需要獲得記憶體資源或者其他更多的資源。在Java中更是如此,虛擬機器甚至試圖跟蹤每個物件,以便能夠在物件銷燬後進行垃圾回收。所以,提高效率的一個手段就是儘可能減少物件建立和銷燬的次數,這就是“池化資源”技術產生的原因
執行緒池的使用
ExecutorService:執行緒池介面
ExecutorService pool(池名稱) = Executors.常用執行緒池名;
例:
ExecutorService pool = Executors.newSingleThreadExecutor();
執行緒池(前四種常用吧)
- newsingleThreadExecutor
單個執行緒的執行緒池,即執行緒池中每次只有一個執行緒在工作,單執行緒序列執行任務
public class single {
public static void main(String[] args) {
//建立池
ExecutorService pool = Executors.newSingleThreadExecutor();
for(int i = 0;i<5;i++) {
int number = i;
//一個新執行緒加入池
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("現在時間是:"+System.currentTimeMillis()+"第"+number+"個執行緒");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
//關閉池
pool.shutdown();
}
}
看輸出在設定的時間段裡每次只有一個執行緒執行 ,按順序執行
- newfixedThreadExecutor(n)
固定數量的執行緒池,每提交一個任務就是一個執行緒,直到達到執行緒池的最大數量,然後在後面等待佇列前面的執行緒執行或者銷燬
public class fixed {
public static void main(String[] args) {
//建立池,可放置4個執行緒
ExecutorService pool = Executors.newFixedThreadPool(4);
for(int i = 0;i<7;i++) {
int number = i;
//將執行緒加入池
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("現在時間是:"+System.currentTimeMillis()+"第"+number+"個執行緒"+Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}
此時執行並不是有序的,搶資源
- newCacheThreadExecutor
一個可快取的執行緒池。當執行緒池超過了處理任務所需要的執行緒數,那麼就會回收部分閒置執行緒(一般是閒置60s)。當有任務來時而執行緒不夠時,執行緒池又會建立新的執行緒,當執行緒夠時就呼叫池中執行緒。適用於大量的耗時較少的執行緒任務。
可能導致記憶體溢位,一般使用newFixedThreadPool代替
public class cache {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
int number = i;
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(
System.currentTimeMillis() + "第" + number + "個執行緒" + Thread.currentThread().getName());
}
});
}
}
}
此時一直只有一個執行緒執行,因為每個時間段內總有閒置的執行緒。
/**
* Thread.sleep寫線上程裡面的時候,只是讓執行緒在執行的過程中休眠2s,並沒有執行後休眠2s
* 如果Thread.sleep寫在run方法裡面,for迴圈中依舊沒有閒置的執行緒,會創新的執行緒
*/
- newScheduleThreadExecutor
一個大小無限的執行緒池,但是核心執行緒數量是固定的,非核心執行緒無限制,並且非核心執行緒一旦閒置立刻回收。此執行緒池支援定時以及週期性執行任務的需求,即該執行緒池可給定延遲執行的命令或者定時執行命令。該執行緒池多用於執行延遲任務或者固定週期的任務。
public class schedule {
public static void main(String[] args) {
//設定池中核心執行緒數量2
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
System.out.println("現在時間"+System.currentTimeMillis());
/**
* pool.schedule(callable, delay, unit)
* callable - 要執行的功能
delay - 從現在開始延遲執行的時間
unit - 延遲引數的時間單位
*/
pool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("現在時間"+System.currentTimeMillis());
}
}, 4, TimeUnit.SECONDS);//設定延遲4s執行
}
}
- newSingleThreadScheduledExecutor
建立只有一條執行緒的執行緒池,他可以在指定延遲後執行執行緒任務
- newWorkStealingPool
會更加所需的並行層次來動態建立和關閉執行緒。它同樣會試圖減少任務佇列的大小,所以比較適於高負載的環境。同樣也比較適用於當執行的任務會建立更多工,如遞迴任務