日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java ee api_Java EE并发API教程

發布時間:2023/12/3 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java ee api_Java EE并发API教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

java ee api

這是一個示例章節,摘自Francesco Marchioni編輯的WildFly上的實用Java EE 7開發 。

本章討論了新的Java EE并發API(JSR 236) ,它概述了使用一組托管資源在Java EE容器上并行執行任務的標準方法。 為了描述如何在您的應用程序中使用此API,我們將遵循以下路線圖:

  • 并發實用工具簡介
  • 如何使用ManagedExecutorService利用異步任務
  • 如何使用ManagedScheduledExecutorService在特定時間安排任務
  • 如何創建動態代理對象,以添加Java EE環境中可用的上下文信息
  • 如何使用ManagedThreadFactory創建托管線程以供您的應用程序使用

并發實用工具概述

在Java EE 7之前,在Java EE容器中執行并發任務是眾所周知的危險做法,有時甚至被容器禁止:

“企業bean不得嘗試管理線程。 企業bean不得嘗試啟動,停止,掛起或恢復線程,也不能嘗試更改線程的優先級或名稱。 企業bean不得嘗試管理線程組”

實際上,通過使用J2SE API在Java EE容器中創建自己的非托管線程,將無法保證將容器的上下文傳播到執行任務的線程。

唯一可用的模式是使用異步EJB消息驅動Bean ,以便以異步方式執行任務。 通常,這足以用于簡單的觸發和遺忘模式,但對Threads的控制仍位于Container的手中。

通過Java EE并發API(JSR 236),您可以將java.util.concurrent API的擴展用作托管資源 ,即由Container進行管理。 與標準J2SE編程的唯一區別是,您將從容器的JNDI樹中檢索托管資源。 但是,您仍將使用屬于java.util.concurrent包的一部分的Runnable接口或類,例如Future或ScheduledFuture 。

在下一節中,我們將從最簡單的示例開始,該示例使用ManagedExecutorService執行異步任務。

使用ManagedExecutorService提交任務

為了創建我們的第一個異步執行,我們將展示如何使用ManagedExecutorService ,它擴展了Java SE ExecutorService以提供用于提交要在Java EE環境中執行的任務的方法。 通過使用此托管服務,容器的上下文將傳播到執行任務的線程:ManagedExecutorService包含在應用程序服務器的EE配置中:

<subsystem xmlns="urn:jboss:domain:ee:2.0">. . .<concurrent>. . . .<managed-executor-services><managed-executor-service name="default"jndi-name="java:jboss/ee/concurrency/executor/default"context-service="default" hung-task-threshold="60000"core-threads="5" max-threads="25" keepalive-time="5000"/></managed-executor-services>. . . .</concurrent></subsystem>

為了創建我們的第一個示例,我們從容器的JNDI上下文中檢索ManagedExecutorService,如下所示:

@Resource(name = "DefaultManagedExecutorService")ManagedExecutorService executor;

通過使用ManagedExecutorService實例,您可以提交可以實現java.lang.Runnable接口或java.util.concurrent.Callable接口的任務。

Callable接口提供了一種call()方法,該方法可以返回任何泛型類型,而不是使用run()方法。

編寫一個簡單的異步任務

因此,讓我們看一個簡單的Servlet示例,該示例使用ManagedExecutorService觸發異步任務:

@WebServlet("/ExecutorServlet")public class ExecutorServlet extends HttpServlet {@Resource(name = "DefaultManagedExecutorService")ManagedExecutorService executor;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter writer = response.getWriter(); executor.execute(new SimpleTask()); writer.write("Task SimpleTask executed! check logs"); }}

在我們的示例中,類SimpleTask通過提供并發執行來實現Runnable接口。

public class SimpleTask implements Runnable {@Overridepublic void run() {System.out.println("Thread started.");}}

從異步任務中檢索結果

上述任務是腳踏實地的好選擇; 正如您可能已經注意到的那樣,無法攔截Task的返回值。 另外,在使用Runnable時,您必須使用不受限制的異常(如果run( )拋出了一個檢查的異常,誰會捕獲它呢?)您無法將run()調用封裝在處理程序中,因為您沒有編寫調用它的代碼)。

如果你想克服這個限制,那么你可以實現一個java.util.concurrent.Callable接口相反,它提交給ExecutorService的,并與等待結果FutureTask.isDone()的返回ExecutorService.submit()

讓我們看一下Servlet的新版本,它捕獲了一個名為CallableTask的Task的結果:

@WebServlet("/CallableExecutorServlet")public class CallableExecutorServlet extends HttpServlet {@Resource(name = "DefaultManagedExecutorService")ManagedExecutorService executor;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {PrintWriter writer = response.getWriter();Future<Long> futureResult = executor.submit(new CallableTask(5)); while (!futureResult.isDone()) {// Waittry {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}try {writer.write("Callable Task returned " +futureResult.get());} catch ( Exception e) {e.printStackTrace();} }}

從代碼中可以看到,我們正在使用isDone( )方法輪詢任務完成情況。 任務完成后,我們可以調用FutureTask的get( )方法并獲取返回值。

現在,讓我們看一下我們的CallableTask實現,在我們的示例中,該實現返回一個數字總和的值:

public class CallableTask implements Callable<Long> {private int id;public CallableTask(int id) {this.id = id;}public Long call() {long summation = 0;for (int i = 1; i <= id; i++) {summation += i;}return new Long(summation);}}

在我們的示例中,我們要做的就是實現call方法,該方法返回Integer,該Integer最終將通過Future接口的get方法來收集。

如果您的Callable任務引發了Exception,則FutureTask.get()也將引發Exception,并且可以使用Exception.getCause()來訪問原始Exception。

監視未來任務的狀態

在上面的示例中,我們正在使用FutureTask.isDone()方法檢查Future Task的狀態。 如果需要對Future Task生命周期進行更準確的控制,則可以實現javax.enterprise.concurrent.ManagedTaskListener實例,以便接收生命周期事件通知。

這是我們增強的Task,它實現了taskSubmitting , taskStarting , taskDone和taskAborted方法:

public class CallableListenerTask implements Callable<Long>,ManagedTaskListener {private int id;public CallableListenerTask(int id) {this.id = id;}public Long call() {long summation = 0;for (int i = 1; i <= id; i++) {summation += i;}return new Long(summation);}public void taskSubmitted(Future<?> f, ManagedExecutorService es,Object obj) {System.out.println("Task Submitted! "+f);}public void taskDone(Future<?> f, ManagedExecutorService es, Object obj,Throwable exc) {System.out.println("Task DONE! "+f);}public void taskStarting(Future<?> f, ManagedExecutorService es,Object obj) {System.out.println("Task Starting! "+f);}public void taskAborted(Future<?> f, ManagedExecutorService es,Object obj, Throwable exc) {System.out.println("Task Aborted! "+f);}}

生命周期通知按以下順序調用:

  • taskSubmitting :關于將任務提交給執行者
  • taskStarting :在實際啟動任務之前
  • taskDone :任務完成時觸發
  • taskAborted :當用戶調用futureResult.cancel()時觸發

在異步任務中使用事務

在分布式Java EE環境中,要確保并發任務執行也能正確執行事務,這是一項艱巨的任務。 Java EE并發API依靠Java事務API(JTA)通過javax.transaction.UserTransaction來支持其組件頂部的事務,該操作用于顯式劃分事務邊界。

以下代碼顯示可調用任務如何從JNDI樹中檢索UserTransaction,然后啟動并提交與外部組件(EJB)的事務:

public class TxCallableTask implements Callable<Long> {long id;public TxCallableTask(long i) {this.id = i;}public Long call() {long value = 0;UserTransaction tx = lookupUserTransaction();SimpleEJB ejb = lookupEJB();try {tx.begin();value = ejb.calculate(id); // Do Transactions heretx.commit();} catch (Exception e) {e.printStackTrace();try { tx.rollback(); } catch (Exception e1) { e1.printStackTrace(); }}return value;}// Lookup EJB and UserTransaction here ..}

這種方法的主要局限性在于,盡管上下文對象可以開始,提交或回滾事務,但是這些對象無法加入父組件事務。

使用ManagedScheduledExecutorService安排任務

ManagedScheduledExecutorService擴展了Java SE ScheduledExecutorService以提供用于提交延遲或定期任務以在Java EE環境中執行的方法。 至于其他托管對象,您可以通過JNDI查找獲得ExecutorService的實例:

@Resource(name ="DefaultManagedScheduledExecutorService") ManagedScheduledExecutorService scheduledExecutor;

一旦有了對ExecutorService的引用,便可以在其上調用schedule方法以提交延遲或定期的任務。 就像ManagedExecutors一樣,ScheduledExecutors也可以綁定到Runnable接口或Callable接口。 下一節將介紹這兩種方法。

提交一個簡單的ScheduledTask

以最簡單的形式提交計劃任務需要設置計劃表達式并將其傳遞給ManagedSchedulerExecutor服務。 在此示例中,由于調用了schedule( )方法,我們將創建一個延遲的任務,該任務僅在10秒內運行一次:

@WebServlet("/ScheduledExecutor") public class ScheduledExecutor extends HttpServlet {@Resource(name ="DefaultManagedScheduledExecutorService")ManagedScheduledExecutorService scheduledExecutor;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {PrintWriter writer = response.getWriter(); ScheduledFuture<?> futureResult = scheduledExecutor.schedule(new SimpleTask(), 10,TimeUnit.SECONDS);writer.write("Waiting 10 seconds before firing the task");}}

如果需要重復計劃任務,則可以使用scheduleAtFixedRate方法,該方法將觸發任務之前的時間,每次重復執行之前的時間和TimeUnit作為輸入。 請參閱以下示例,該示例在初始延遲1秒后每10秒秒調度一次任務:

ScheduledFuture<?> futureResult = scheduledExecutor. scheduleAtFixedRate (new SimpleTask(),1, 10,TimeUnit.SECONDS);

捕獲計劃執行的結果

如果需要從計劃執行的任務中獲取返回值,則可以使用schedule方法返回的ScheduledFuture接口。 這是一個示例,它捕獲了我們先前編碼的階乘示例Task的結果:

ScheduledFuture<Long> futureResult =scheduledExecutor.schedule(new CallableTask(5), 5, TimeUnit.SECONDS); while (!futureResult.isDone()) { try {Thread.sleep(100); // Wait} catch (InterruptedException e) { e.printStackTrace();}} try {writer.write("Callable Task returned " +futureResult.get());} catch ( Exception e) {e.printStackTrace();}

使用ManagedThreadFactory創建托管線程

javax.enterprise.concurrent.ManagedThreadFactory等效于J2SE ThreadFactory,可用于創建自己的線程。 為了使用ManagedThreadFactory,您需要照常從JNDI注入它:

@Resource(name ="DefaultManagedThreadFactory")ManagedThreadFactory factory;

從工廠創建自己的托管線程(與ManagedExecutorService創建的托管線程相比)的主要優點是,您可以設置一些典型的線程屬性(例如名稱或優先級),并且可以創建J2SE Executor服務的托管版本。 。 以下示例將向您展示如何。

從工廠創建托管線程

在此示例中,我們將使用DefaultManagedThreadFactory創建并啟動新線程。 從代碼中可以看到,一旦我們創建了Thread類的實例,就可以為其設置有意義的名稱并將其與優先級相關聯。 然后,我們將線程與我們的SimpleTask關聯,該SimpleTask在控制臺上記錄一些數據:

@WebServlet("/FactoryExecutorServlet")public class FactoryExecutorServlet extends HttpServlet {@Resource(name ="DefaultManagedThreadFactory")ManagedThreadFactory factory;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {PrintWriter writer = response.getWriter();Thread thread = factory.newThread(new SimpleTask());thread.setName("My Managed Thread");thread.setPriority(Thread.MAX_PRIORITY);thread.start();writer.write("Thread started. Check logs");}}

現在檢查您的服務器日志:毫無疑問,檢測自己創建的線程的輸出會更容易:

14:44:31,838 INFO [stdout] (My Managed Thread) Simple Task started

在分析線程轉儲時,收集有關線程名稱的信息特別有用,并且線程名稱是跟蹤線程執行路徑的唯一線索。

使用托管執行器服務

java.util.concurrent.ExecutorService接口是一種標準的J2SE機制,已大大取代了使用直接線程執行異步執行的方法。 與標準Thread機制相比,ExecutorService的主要優點之一是您可以定義一個實例池來執行您的作業,并且您可以采用一種更安全的方式來中斷您的作業。

在企業應用程序中使用ExecutorService很簡單:只需將Managed ThreadFactory的實例傳遞給ExecutorService的構造函數即可。 在以下示例中,我們使用SingletonEJB在其方法getThreadPoolExecutor中將ExecutorService作為服務提供:

@Singletonpublic class PoolExecutorEJB {private ExecutorService threadPoolExecutor = null;int corePoolSize = 5;int maxPoolSize = 10;long keepAliveTime = 5000;@Resource(name = "DefaultManagedThreadFactory")ManagedThreadFactory factory;public ExecutorService getThreadPoolExecutor() {return threadPoolExecutor;}@PostConstructpublic void init() { threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, keepAliveTime, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(10), factory); }@PreDestroypublic void releaseResources() {threadPoolExecutor.shutdown(); }}

ThreadPoolExecutor在其構造函數中包含兩個核心參數: corePoolSize和maximumPoolSize 。 當在方法中提交新任務且運行的線程數少于corePoolSize時,即使其他工作線程處于空閑狀態,也會創建一個新線程來處理請求。 如果運行的線程數大于corePoolSize但小于maximumPoolSize,則僅在隊列已滿時才創建新線程。

然后,如以下示例所示, ExecutorService用于啟動新的異步任務,其中在Servlet中提供了Runnable的匿名實現:

@WebServlet("/FactoryExecutorServiceServlet") public class FactoryExecutorServiceServlet extends HttpServlet {@EJB PoolExecutorEJB ejb;protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {final PrintWriter writer = response.getWriter();writer.write("Invoking ExecutorService. Check Logs.");ExecutorService executorService = ejb.getThreadPoolExecutor();executorService.execute(new Runnable() {public void run() {System.out.println("Message from your Executor!");}});}}

PoolExecutorEJB終止后,ExecutorService也將在Singleton Bean的@PreDestroy方法中完成,該方法將調用ThreadPoolExecutor的shutdown()方法。 ExecutorService不會立即關閉,但將不再接受新任務,并且一旦所有線程都完成了當前任務,ExecutorService就會關閉。

使用動態上下文對象

動態代理是有用的Java調整,可用于使用java.lang.reflect.Proxy API創建接口的動態實現。 您可以將動態代理用于多種不同目的,例如數據庫連接和事務管理,用于單元測試的動態模擬對象以及其他類似于AOP的方法攔截目的。

在Java EE環境中,可以使用一種稱為動態上下文代理的特殊類型的動態代理

動態上下文對象最有趣的功能是將JNDI命名上下文,類加載器和安全性上下文傳播 到代理對象 。 在將J2SE實現引入企業應用程序并希望在容器的上下文中運行它們的情況下,這很有用。

以下代碼片段顯示了如何將上下文對象注入到容器中。 由于上下文對象還需要您可以向其提交任務的ExecutorService,因此也會注入ThreadFactory:

@Resource(name ="DefaultContextService")ContextService cs;@Resource(name ="DefaultManagedThreadFactory")ManagedThreadFactory factory;

在下一節中,我們將展示如何使用修訂版的Singleton EJB創建動態上下文對象。

執行上下文任務

下面的示例演示如何為Callable任務觸發上下文代理。 為此,我們將同時需要ManagedThreadfactory和ContextService。 我們的ContextExecutor EJB首先將在其init方法中創建ThreadPoolExecutor。 然后,在Submit方法內,創建可調用任務的新上下文代理,并將其提交給ThreadPool執行器。

這是我們的ContextExecutorEJB的代碼:

@Singletonpublic class ContextExecutorEJB {private ExecutorService threadPoolExecutor = null;@Resource(name = "DefaultManagedThreadFactory")ManagedThreadFactory factory;@Resource(name = "DefaultContextService")ContextService cs;public ExecutorService getThreadPoolExecutor() {return threadPoolExecutor;}@PostConstructpublic void init() {threadPoolExecutor = new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS,new ArrayBlockingQueue>Runnable>(10), factory);}public Future>Long> submitJob(Callable>Long> task) {Callable>Long> proxy = cs.createContextualProxy(task, Callable.class);return getThreadPoolExecutor().submit(proxy);}}

CallableTask類比我們的第一個示例復雜一點,因為它將記錄有關javax.security.auth.Subject信息,該信息包含在調用方線程中:

public class CallableTask implements Callable<Long> {private int id;public CallableTask(int id) {this.id = id;}public Long call() {long summation = 0;// Do calculationSubject subject = Subject.getSubject(AccessController.getContext());logInfo(subject, summation); // Log Traces Subject identityreturn new Long(summation);}private void logInfo(Subject subject, long summation) { . . }}

以下是向我們的SingletonEJB提交新的上下文任務的簡單方法:

@EJB ContextExecutorEJB ejb; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { CallableTask task = new CallableTask(5);ejb.submitJob(task);}

建立你的例子

為了對Java EE API使用并發實用程序,您的應用程序需要以下Maven依賴項:

<dependency><groupId>org.jboss.spec.javax.enterprise.concurrent</groupId><artifactId>jboss-concurrency-api_1.0_spec</artifactId><version>1.0.0.Final</version></dependency>


此摘錄摘自《 WildFly上的實用Java EE 7開發 》一書,該手冊是動手實踐指南,其中介紹了最新WildFly應用程序服務器上Java EE 7開發的所有領域。 涵蓋了從基礎組件(EJB,Servlet,CDI,JPA)到Java Enterprise Edition 7中定義的新技術堆棧的所有內容,因此包括新的Batch API,JSON-P Api,并發API,Web套接字,JMS 2.0 API,核心Web服務堆棧(JAX-WS,JAX-RS)。 帶有Arquillian框架和Security API的測試區域完成了本書中討論的主題列表。

翻譯自: https://www.javacodegeeks.com/2014/07/java-ee-concurrency-api-tutorial.html

java ee api

總結

以上是生活随笔為你收集整理的java ee api_Java EE并发API教程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。