Executor API的相關介紹能夠在由Oracle維護的Java SE文檔——High Level Concurrency Objects中找到。Executor API向開發者提供一系列的對象實現高效的線程管理。一般來講,這種高效是由一些線程池機制提供的。 html
線程池 java
線程池負責建立特定數量的工做線程,並在這些工做線程上運行用戶自定義的任務。在這種機制下,最多可運行的用戶自定義任務的數量由線程池的大小和系統資源的利用率決定。 服務器
左側的代碼想用for循環方式在你的程序中建立並執行5000個任務。在不使用線程池的狀況下,試圖激活這5000個任務將會對系統資源形成威脅。經過查看系統中正在運行的程序內活躍任務(線程)的數量,咱們能夠更好地來理解威脅的含義。例如,上圖顯示了在個人機器上同時運行的一系列進程及其所持有的線程。咱們能夠清楚的看到應用程序idea.exe持有71個線程,而其餘的應用程序則使用了較少的線程。所以,若是我有5000個任務而且爲這5000個任務建立了5000個不一樣的線程,這難道意味着我設計了一個好的架構嗎?(固然不是)事實上,若是我把這5000個任務按照必定規則(隨機分配或按優先級分配)安排在特定數量的工做線程上運行,會更高效地利用系統資源並且不會給系統帶來沒必要要的壓力。因爲上面的圖中設定了5個工做線程,這5000個任務在操做系統看來最多隻有5個用戶自定義任務在運行。當一個工做線程執行結束後,會從當前處於等待狀態的任務中選取一個執行,這個過程會持續進行直到全部的任務都執行完成。所以,Java SE 1.5版本推出的Executor API的基本原理是經過提供多種線程池環境實現高效的線程管理。工做線程是線程工廠生產的通用線程。ExecutorService和ScheduledExecutorService是Executor API中的基本接口。這些接口的實現多是Executors類的一系列靜態方法。Java EE 7版本推出的新Concurrency Utilities標準經過容器服務提供這些對象的注入和管理。容器管理的Executor對象以XXXExecutorService和XXXScheduledExecutorService的形式命名,如ManagedExecutorService和ManagedScheduledExecutorService標識了它是可管理的。你能夠查看這些接口的UML圖,瞭解Java SE Executor API接口間的繼承關係。 架構
以「Managed」開頭的接口基本上和Java 1.5版本推出的Executor API組件提供相同的操做。不一樣之處在於,其建立的對象將以容器資源(container resources)的形式提供給開發者。 併發
容器資源是由應用服務器管理的特殊對象。DataSources、JMS resources以及Concurrency Utilities中的Concurrency units都屬於容器資源。 oracle
容器資源是駐留在應用服務器上並提供特定功能的對象。這些對象能夠經過 JNDI( Java Naming and Directory Interfaces )標準進行訪問 。@Resource 註解和 Context接口類型的對象(如:InitialContext)基本上能夠實現對這些對象的訪問。
建立併發資源 java-ee
支持Java EE 7版本的應用服務器可以建立Concurrency Utilities中可管理的Executor對象。例如,這個建立過程能夠經過Glassfish 4的asadmin命令集或者Glassfish管理員控制檯直觀地定義出來。 ide
Glassfish應用服務器/bin目錄下的asadmin tool用於命令行操做。下面的例子使用了asadmin tool,並經過create-managed-executor-service 命令和create-managed-scheduled-executor-service命令建立可管理的Executor對象。由於容器資源在被提供給應用環境時攜帶着聽從JNDI標準定義的訪問表達式,因此須要在控制檯中輸入表明該容器資源的惟一訪問標識符。 url
在Glassfish管理員控制檯中可以看到可管理的Executor對象。與此同時,在管理員控制檯中也可以進行添加和修改。 idea
Glassfish 4的容器資源顯示在控制檯的Resources標籤下。併發資源顯示在子標籤Concurrent Resources下。而咱們建立的用於容器管理的ManagedExecutorService和ScheduledManagedExecutorService 資源就能在這個子標籤下找到。由應用服務器內部定義的帶__default前綴的併發資源也是可用的。若是須要的話,也可使用現有的默認資源。
獲取Concurrency Utilities中的資源
注入的@Resource註解和InitialContext對象可以訪問駐留在應用服務器上的併發資源。@Resource 註解和InitialContext對象提供標準的JNDI訪問不只適用於併發資源,還適用於其餘容器資源。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
@WebServlet(urlPatterns ="/kodcu",name ="KodcuServlet")
publicclassKodcuServletextendsHttpServlet {
@Resource// (1)
privateManagedExecutorService defaultmanagedExecutorService;
@Resource// (2)
privateManagedScheduledExecutorService defaultScheduledExecutorService;
@Resource(lookup ="concurrent/KodcuExecutor")// (3)
privateManagedExecutorService managedExecutorService;
@Resource(lookup ="concurrent/KodcuScheduledExecutor")// (4)
privateManagedScheduledExecutorService scheduledExecutorService;
@Override
protectedvoiddoGet(HttpServletRequest req, HttpServletResponse resp)throwsServletException, IOException {
...
InitialContext context=newInitialContext();// (5)
ManagedExecutorService managedExecutorServiceWithContext = (ManagedExecutorService) context.lookup("concurrent/KodcuExecutor");
...
}
}
|
上面的Servlet類,使用@Resource註解獲取默認的併發資源(編號1和編號2)以及在命令行中指定特定JNDI名稱所建立的併發資源(編號3和編號4)。@Resource註解的lookup字段存放着相應對象的惟一資源訪問標識符,該標識符聽從JNDI標準。當@Resource註解沒有設定lookup字段時,注入的是帶有__default前綴的默認JNDI資源。除了使用註解的方法以外,在編號5的代碼段中,使用InitialContext對象根據JNDI名稱獲取相應的併發資源。
本文的示例源碼連接以下:
http://en.kodcu.com/2013/10/java-ee-7-concurrency-utilities-spesification/