1. 程式人生 > >Java執行緒池的認識、常用執行緒池的分析

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 

會更加所需的並行層次來動態建立和關閉執行緒。它同樣會試圖減少任務佇列的大小,所以比較適於高負載的環境。同樣也比較適用於當執行的任務會建立更多工,如遞迴任務