1. 程式人生 > >關於多執行緒和執行緒安全相關討論(三)

關於多執行緒和執行緒安全相關討論(三)

三:執行緒池的相關總結

1.執行緒池的意義:

執行緒雖然好用,但是如果建立了大量的執行緒,會拖垮整個程式,甚至可能會出現OOM異常;另一方面,大量的執行緒被GC的時候,也會產生巨大的壓力,延長GC的停頓時間。

其次,執行緒在被建立和銷燬的時候,也是會消耗系統的記憶體和資源的。

說的簡單一點,你們JDBC連線是不是用連線池的,現在基本上不會有人去建立JDBC連線,然後去使用它了,基本都是利用連線池,取得池內的連線。執行緒池也是一樣的概念。我們不再建立執行緒,而是從執行緒池中去取得,由執行緒池去控制和管理執行緒。

2.最基本的執行緒池:

JDK對於多執行緒的控制,專門提供了一套Executor

框架。java.util.concurrentjava的併發包。其中Executors類是執行緒池工廠,通過Executors類我們可以得到不同功能的執行緒池。

1)newFixedThreadPool:構造方法時必須傳入執行緒數(Int),這是一個固定傳入引數的執行緒數的執行緒池

2)newSingleThreadPool:這是一個固定只有一個執行緒的執行緒池

3)newCacheThreadPool:這是一個最大執行緒數無上限的執行緒池

這三個執行緒池,看似功能不同,但是其實他們都是ThreadPoolExecutor類的封裝,我們可以看一下,關於這個ThreadPoolExecutor

這個類的構造方法;

最完整的構造方法裡面構造引數有7個,分別是corePoolSizemaximumPoolSizekeepActiveTimeunitworkQueuethreadFactoryRejectedExecutionHandler

corePoolSize 表示執行緒池的核心執行緒數,

maximumPoolSize 表示執行緒池最大執行緒數

keepActiveTime 表示線上程池中,空閒執行緒的存活時間

Unit 表示上面存活時間的時間單位

workQueue 表示執行緒池中的任務佇列

threadFactory 表示執行緒池中的執行緒工廠,基本上都是選擇預設的,關於這個東西,阿里雲的程式碼規範對這個執行緒工廠做了一個補充,大家可以去看看

RejectedExecutionHandler 表示的是這個執行緒池中的拒絕策略,JDK預設的拒絕策略是AbortPolicy

我覺得知道了連線池,再去看執行緒池,其實都是差不多的,所以什麼核心執行緒數,最大執行緒數,存活時間的我就不多說了,覺得可以說一下的是workQueueRejectedExecutionHandler

一般來說,任務佇列(workQueue)有以下的幾種,

1.SynchronousQueue(直接提交佇列),這個任務佇列,他沒有容量,基本就是屬於有了任務,就將任務提交給執行緒池,讓執行緒池建立新的執行緒,直至執行緒池中的活躍執行緒大於最大執行緒數,這個時候,執行緒池就直接執行拒絕策略(RejectedExecutionHandler

2.ArrayBlockingQueue(有界佇列),如果要使用這個任務佇列,就必須在初始化的時候,傳入容量引數,代表這個任務佇列的最大容量。對於這個任務佇列而言,當執行緒池中的活躍執行緒數等於核心執行緒數之後,這個佇列就不提交任務了,直到任務堆積過多,超過了容量引數,這個時候,任務佇列才會繼續提交任務,讓執行緒池開始生成新的執行緒,直到活躍執行緒數大於最大執行緒數,而這個時候,執行緒池就開始執行拒絕策略了

3.LinkedBlockingQueue(無界佇列),這個佇列,他的容量是無限的,他可以不斷的增長,直到吃完系統的所有資源。對於這個佇列而言,當執行緒池中的活躍執行緒數等於核心執行緒數之後,他也同樣不會提交任務,但是和有界佇列不同,因為他的容量是無限的,所以不存在會使用最大執行緒數的時候,也不存在拒絕策略,除非你的系統先掛掉

4.PriorityBlockingQueue(優先佇列),這個佇列,是一個特殊的無界佇列,所以在對待執行緒池內的執行緒數的控制方面,是和無界佇列一致的。對於有界佇列和無界佇列而言,他們其實都是按照先進先算,後進後算的方法來向執行緒池傳遞任務的。但是優先佇列正如名字一樣,他是會根據任務自己的優先順序來決定先後執行順序的。所以換句話說,如果你要使用優先佇列,那麼就要讓你的任務去實現Comparable介面,重寫裡面的compareTo方法,具體可以參考下面的程式碼

package com.liu.javathread.priorityblockingqueue;

public class MyThread implements Runnable, Comparable<MyThread>{

	protected String name;

	public MyThread(String name) {
		super();
		this.name = name;
	}

	public MyThread() {
		
	}

	@Override
	public int compareTo(MyThread o) {
		// 這是自身這個執行緒的數值
		int me = Integer.parseInt(this.name.split("_")[1]);
		// 傳參的執行緒的資料
		int other = Integer.parseInt(o.name.split("_")[1]);
		if(me > other){
			return 1;
		}else if(me < other){
			return -1;
		}else{
			return 0;
		}
	}

	@Override
	public void run() {
		try {
			// 系統沉睡模擬工作任務
			Thread.sleep(1000);
			System.out.println(name+" ");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	
	
}
package com.liu.javathread.priorityblockingqueue;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class MyThreadMain {

	public static void main(String[] args) {
		
		ExecutorService executor = new ThreadPoolExecutor(10, 100, 2, TimeUnit.SECONDS, new PriorityBlockingQueue<Runnable>());
		for(int i=0;i<1000;i++){
			executor.execute(new MyThread("testThread_"+Integer.toString(999-i)));
		}
	}

}

而關於拒絕策略,我覺得一般來說,選擇預設的AbortPolicy就可以了,這個拒絕策略意思是直接丟擲異常,阻止系統繼續工作

另外的拒絕策略,CallerRunsPolicyDiscardOledestPolicy,DiscardPolicy這些策略,大家有興趣可以自己研究一下,另外如果說,你對於這些拒絕策略都不滿意,可以自己去重新實現。RejectedExecutionHandler 這個東西其實他是一個介面,上述的那些都是他的實現。

最後大家可以去看一下,之前我們說的三個JDK定義好的執行緒池,他們的核心執行緒數,最大執行緒數,存活時間,包括任務佇列分別都是些什麼。這對於我們已經選擇JDK自帶的執行緒池有很大的幫助

3.擴充套件執行緒池:

阿里巴巴的程式碼規範中,建議我們使用執行緒池,而且最好不是使用JDK自帶的執行緒池,而是利用最基本的執行緒池ThreadPoolExecutor,不僅僅是因為我們可以自由的選擇任務佇列,拒絕策略,更多的是因為,這個執行緒池具有可擴充套件性

首先具體的來說,最具代表性的就是beforeExecutor()afterExecutor()這兩個方法,這兩個方法看方法名就知道,他們分別是線上程池內執行緒啟動之前和執行緒結束之後分別去呼叫的。

我們可以通過繼承ThreadPoolExecutor這個類,然後重寫這兩個方法,去實現我們的業務,我個人覺得這個在除錯的時候比較有用,至少你可以知道你的多個執行緒在執行前和執行後的狀態。具體可以參考MyThreadPool這個檔案。另外如果大家有興趣的話,可以去找一下為什麼執行緒池內部在呼叫工作執行緒的時候,會呼叫這兩個方法

相關推薦

JAVA執行併發基礎面試問答轉載

  多執行緒和併發問題是Java技術面試中面試官比較喜歡問的問題之一。在這裡,從面試的角度列出了大部分重要的問題,但是你仍然應該牢固的掌握Java多執行緒基礎知識來對應日後碰到的問題。(校對注:非常贊同這個觀點) Java多執行緒面試問題 1. 程序和執行緒之間有什麼不同? 一個程序是一個獨立(

Objective-C高階程式設計 iOS與OS X執行記憶體管理 讀書筆記

1.2.2 記憶體管理原則: 自己生成的物件,自己所持有 非自己生成的物件,自己也能持有 不再需要自己持有的物件時釋放 非自己持有的物件無法釋放 自己生成的物件,自己所持有 //自己生成並持有物件 id obj = [[NSObject alloc] init]; //自己持有物件   

JAVA併發:執行程式設計之同步“監視器monitor”

在JAVA虛擬機器中,每個物件(Object和class)通過某種邏輯關聯監視器,為了實現監視器的互斥功能,每個物件(Object和class)都關聯著一個鎖(有時也叫“互斥量”),這個鎖在作業系統書籍中稱為“訊號量”,互斥(“mutex”)是一個二進位制的訊號量。 如果一個執行緒擁有了某些資料的鎖,其他的

相關圖的鄰接矩陣表示C++及最最小生成樹演算法primkruskal

一.測試用圖 鄰接矩陣表示: //prim注意是無向圖 vector<vector<int>> p(6, vector<int>(6, INF));//類似dijikstra,沒有邊的點設為INF p[0][1] = 10;

Java線程編程模式實戰指南:Two-phase Termination模式

增加 row throws mgr 額外 finally join table 還需 停止線程是一個目標簡單而實現卻不那麽簡單的任務。首先,Java沒有提供直接的API用於停止線程。此外,停止線程時還有一些額外的細節需要考慮,如待停止的線程處於阻塞(等待鎖)或者等待狀態(等

YII用戶註冊用戶登錄之模型中規則制定分析

模型 als del 郵箱 收信 com unique mark div 3 模型中規則制定和分析 YII模型主要分為兩類,一個數據模型,處理和數據庫相關的增刪改查。繼承CActiveRecord。還有一個是表單模型,繼承CFormModel。不與數據庫進行交互。操作

部署標準交換機分布式交換機

部署標準交換機和分布式交換機實驗目標:部署標準交換機和分布式交換機實驗要求:標準交換機的配置:分別在兩臺esxi主機中添加6塊物理網卡,橋接到vmnet1。分別在兩臺esxi主機配置標準交換機,將vSwitch0交換機添加一個物理網卡,實現負載均衡和容錯。分別在兩臺esxi主機中,將vSwitch0交換機添加

小白學習安全測試——掃描工具-Nikto使用

sdn plugins 技術 use 開發 服務器 update 自動 網站目錄 掃描工具-Nikto #基於WEB的掃描工具,基本都支持兩種掃描模式。代理截斷模式,主動掃描模式 手動掃描:作為用戶操作發現頁面存在的問題,但可能會存在遺漏 自動掃描:基於字典,提高速度,但存

ReduxReact-Redux的實現:中間件的原理applyMiddleware、Thunk的實現

調用 map 介紹 typeof 觀察者 ets 返回 async 基本原理 現在我們的Redux和React-Redux已經基本實現了,在Redux中,觸發一個action,reducer立即就能算出相應的state,如果我要過一會才讓reducer計算state呢怎麽辦

PHP、MySQLJavaScript學習手冊筆記

php efault ava asc 學習 mys comm 否則 hello 第四章 條件語句 <?php if ($cond<100) { echo "cond <100"; } else { echo "cond >100"; }

angularjsajax的結合使用

ESS 靈活運用 告訴 公司 紅色 success body 說了 spa 轉眼九月份了,忙忙碌碌 發現今年還沒開過張,寫一篇吧。 15年在空閑時就倒騰過angularjs那玩意兒 ,覺得還是挺好的,李金龍那厚厚的一本書,只不過沒有系統化應用。最主要的是原來有一個東西沒有

從零開始Rtklib解讀篇-簡單的程式設計理論演算法及結構分析

1. argc和argv argc和argv中的arg指的是"引數",首先是一個計算提供的引數到程式,第二個是對字串陣列的指標 argc: 整數,用來統計你執行程式時送給main函式的命令列引數的個數 * argv[ ]: 字串陣列,用來存放指向你

安全程式設計

1.Java中,什麼是建構函式?什麼是建構函式過載?         當一個新物件被建立的時候,建構函式會自動呼叫。每一個類都有建構函式。在我們沒有給類提供建構函式的時候,Java編譯器會自動為這個類建立一個預設的建構函式。    

安裝Git建立一個倉庫repository

這裡講的是windows 安裝Git: 要使用Git,第一步當然是安裝Git了。根據你當前使用的平臺來閱讀下面的文字: 在Windows上使用Git,可以從Git官網直接下載安裝程式,然後按預設選項安裝即可。 安裝完成後,在開始選單裡找到“Git”->“Git Bash”,蹦出一個類似

Web安全系列:XSS 攻擊進階挖掘漏洞

前言 目前來說,XSS 的漏洞型別主要分為三類:反射型、儲存型、DOM型,在本篇文章當中會以permeate生態測試系統為例,分析網站功能,引導攻擊思路,幫助讀者能夠快速找出網站可能存在的漏洞。 反射型 XSS 挖掘 現在筆者需要進行手工XSS漏洞挖掘,在手工挖掘之前筆者需要先逛逛網站有哪些功能點,如下圖是

Quartz學習——SpringQuartz整合詳解

Spring是一個很優秀的框架,它無縫的集成了Quartz,簡單方便的讓企業級應用更好的使用Quartz進行任務的排程。下面就對Spring整合Quartz進行簡單的介紹和示例講解!和上一節 Quartz學習——2、簡單入門示例Demo 的流程相似,介紹Spring和Quar

複習之shiro安全框架——通過jdbcRealm連線資料庫

shiro提供jdbcRealm連線資料庫 這裡要連線資料庫所有要依賴一些jar包 <dependency> <groupId>org.apache.shiro</groupId>

C++C語言的區別——const

(1).c檔案與.cpp檔案中const的區別 我們先引用兩個大致相同的程式碼段: c檔案中:  C++檔案中: 可以看到兩段近似相同的程式碼竟然出現了不同的輸出。 他們的主要區別如下,這就可以解釋為什麼C++檔案中列印的值為10了。  (2

Java HTTP 的那些事 代理認證

前面一篇部落格介紹了在 Java 中使用 HttpURLConnection 和 HttpClient 通過代理訪問 HTTP 站點的方法,但是可以看到程式碼中使用的代理都是免費公開的代理,不需要使用者名稱密碼就能直接訪問。由於網際網路上公開的代理安全性不能保證,這種代

程式設計師之網路安全系列:資料加密之對稱加密演算法

系列目錄: 前文回顧 假如,明明和麗麗相互不認識,明明想給麗麗寫一封情書,讓隔壁老王送去 如何保證隔壁老王不能看到情書內容?(保密性) 如何保證隔壁老王不修改情書的內容?(完整性) 如何保證隔壁老王不冒充明明?(身份認證) 如何保證明明不能否認情書是自己寫的?(來源的不可否認) 上一節,我們使用了Ha