版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 1
JSR 236 :适用于 Java EE 应用程序的并发性实用程序 Shing Wai Chan ( 陳成威 ) Anissa Lam ( 梁鈺儀) 专题讲座 ID : CON1468
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 3 以下内容旨在概述产品的总体发展方向。该内容仅供参考,不可纳入任 何合同。其内容不构成提供任何材料、代码或功能的承诺,并且不应该 作为制定购买决策的依据。此处所述有关 Oracle 产品的任何特性或功 能的开发、发布以及相应的日程安排均由 Oracle 自行决定。
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 4 议题 概述 托管对象 上下文和事务 总结 资源
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 5 概述 Java EE 7 的新特性 使用应用程序组件并发性的简单、标准化 API Java SE 并发性实用程序 API (JSR-166) 的扩展 以安全、可靠、一致的方式为 Java EE 应用程序组件添加了底层异步处 理功能 管理和监控异步操作的生命周期
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 6 概述 提供实现这些接口的 4 种类型的托管对象 – ManagedExecutorService – ManagedScheduledExecutorService – ManagedThreadFactory – ContextService 上下文传播 事务管理
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 7 概述 托管对象由 Java EE 产品提供商提供 提供预先配置的默认对象 应用程序通过如下内容查找托管对象 – JNDI 查找 – 的资源注入
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 8 议题 概述 托管对象 上下文和事务 总结 资源
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 9 ManagedExecutorService 用于在由 Java EE 产品提供商提供的线程上异步运行任务 从提交线程捕获容器上下文以应用在执行线程上 非事务性 — 任务应使用其自身的事务 预配置的默认值: – java:comp/DefaultManagedExecutorService 概述
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 10 ManagedExecutorService 由 java.util.concurrent.ExecutorService 扩展而来 – execute 、 submit 、 invokeAll 、 invokeAny – 无新的 API 禁用生命周期 API — 抛出 IllegalStateException awaitTermination 、 isTerminated 、 isShutdown 、 shutdown 、 shutdownNow Future 在任务提交后返回 – 检查执行状态 – 取消任务 – 等待并检索结果 API
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 11 ManagedExecutorService API void execute(Runnable command); Future submit(Callable task); Future submit(Runnable task); Future submit(Runnable task, T result); List > invokeAll(Collection > tasks); List > invokeAll(Collection > tasks, long timeout, TimeUnit unit); T invokeAny(Collection > tasks) T invokeAny(Collection > tasks, long timeout, TimeUnit unit);
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 12 ManagedExecutorService 示例 ManagedExecutorService mes; void someMethod() { Callable c = new Callable<>() { Integer call() { // Interact with a database...return answer. } //Submit the task and do something else. Future result = mes.submit(c);... //Get the result when ready... int theValue = result.get();...
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 13 ManagedExecutorService 示例 2 : // Retrieve all accounts from several account databases in parallel. //JNDI Lookup javax.naming.InitialContext ctx = new InitialContext(); ManagedExecutorService mes = (ManagedExecutorService) ctx.lookup("java:comp/DefaultManagedExecutorService"); // Create a set of tasks to perform the account retrieval. ArrayList > retrieverTasks = new ArrayList >(); retrieverTasks.add(new EISAccountRetriever()); retrieverTasks.add(new RDBAccountRetriever()); // Submit the tasks to the thread pool and wait for completion. List > taskResults= mes.invokeAll(retrieverTasks
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 14 ManagedExecutorService 示例 2 (续) // Retrieve the results from the resulting Future list. ArrayList results = new ArrayList (); for(Future taskResult : taskResults) { try { results.add(taskResult.get()); } catch (ExecutionException e) { Throwable cause = e.getCause(); } return results; public class EISAccountRetriever implements Callable { public Account call() { … } }
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 15 ManagedExecutorService 选择更简化的方法 添加服务质量、持久性或任务分区等更多功能。 可能的选项:(同 GlassFish 4.0 ) – JNDI 名称 – 上下文信息 – 线程优先级 – 挂起任务阈值 配置
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 16 ManagedExecutorService 底层线程池的配置。 – 内核大小 – 最大池大小 – 线程生命周期 – 保持激活 – 任务队列容量 缓存线程池(如 java.util.concurrent.Executors 中所述)。 配置(续)
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 17 ManagedExecutorService 托管线程池执行器组件关系
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 18 ManagedScheduledExecutorService 对于安排任务在线程上运行 – 在指定延迟后运行 – 定期运行 – 按某个定制时间表运行 还会在由 Java EE 容器提供的线程上运行任务 预配置的默认值: java:comp/DefaultManagedScheduledExecutorService 概述
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 19 ManagedScheduledExecutorService 扩展自 – ManagedExecutorService – java.util.concurrent.ScheduledExecutorService 除了 ManagedExecutorService 之外的 API – schedule – scheduleAtFixedRate – scheduleWithFixedDelay 支持定制计划的扩展 API – schedule (带有 Trigger ) API
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 20 ManagedScheduledExecutorService API ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit); ScheduledFuture schedule(Runnable command, long delay, TimeUnit unit); ScheduledFuture scheduleAtFixedFate(Runnable command, long initialDelay, long period, TimeUnit unit); ScheduledFuture scheduledWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit); ScheduledFuture schedule(Runnable command, Trigger trigger); ScheduledFuture schedule(Callable callable, Trigger trigger);
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 21 ManagedScheduledExecutorService 在 GlassFish 4.0 中,配置与 ManagedExecutorService 相同,除了 – 任务队列容量 – 最大池大小 原因:具有无边界队列的固定大小池总是在 ManagedScheduledExecutorService 中使用。 配置
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 22 ManagedScheduledExecutorService 触发器 允许应用程序开发人员为运行任务插入规则。 可以很简单:单一、绝对日期时间 可以包含 Java™ EE 业务日历逻辑 提交时注册到任务 在其注册的所在相同进程内调用
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 23 ManagedScheduledExecutorService 触发器 API boolean skipRun(LastExecution lastExecutionInfo, Date scheduledRunTime) Date getNextRunTime(LastExecution lastExecutionInfo, Date taskScheduledTime)
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 24 ManagedScheduledExecutorService 触发器示例 public class SingleDateTrigger implements Trigger { private Date fireTime; public TriggerSingleDate(Date newDate) { fireTime = newDate; } public Date getNextRunTime( LastExecution lastExecutionInfo, Date taskScheduledTime) { if(taskScheduledTime.after(fireTime)) { return null; } return fireTime; } public boolean skipRun(LastExecution lastExecutionInfo, Date scheduledRunTime) { return scheduledRunTime.after(fireTime); }
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 25 ManagedExecutors javax.enterprise.concurrent 中定义的类的实用程序 如果当前线程是 ManageableThread ,则进行测试 如果当前线程标记为关闭,则进行测试 #managedTask – 返回 Callable/Runnable (也实现 ManagedTask )
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 26 ManagedExecutors API public static boolean isCurrentThreadShutdown() public static Runnable managedTask(Runnable task, ManagedTaskListener taskListener) throws IllegalArgumentException public static Runnable managedTask(Runnable task, Map executionProperties, ManagedTaskListener taskListener) throws IllegalArgumentException public static Callable managedTask(Callable task, ManagedTaskListener taskListener) throws IllegalArgumentException public static Callable managedTask(Callable task, Map executionProperties, ManagedTaskListener taskListener) throws IllegalArgumentException
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 27 Managed[Scheduled]ExecutorService ManagedTask 提交给 Managed[Scheduled]ExecutorService 的任何任务可选 择性地实现 ManagedTask 提供: – 标识信息 – 用于生命周期事件通知的 ManagedTaskListener – 其他执行属性
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 28 Managed[Scheduled]ExecutorService ManagedTask API – Map getExecutionProperties() – ManagedTaskListener getManagedTaskListener() 执行属性 – LONGRUNNING_HINT – IDENTITY_NAME – TRANSACTION SUSPEND USE_TRANSACTION_OF_EXECUTION_THREAD
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 29 Managed[Scheduled]ExecutorService ManagedTaskListener 监视任务的 Future 的状态 使用提交注册到 ManagedExecutorService 当 Future 的状态发生变化时被调用 每个实例均在监听器所注册的相同进程中被调用
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 30 Managed[Scheduled]ExecutorService ManagedTaskListenerAPI void taskSubmitted(Future future, ManagedExecutorService executor, Object task) void taskDone(Future future, ManagedExecutorService executor, Object task, Throwable exception) void taskStarting(Future future, ManagedExecutorService executor, Object task) void taskSubmitted(Future future, ManagedExecutorService executor, Object task)
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 31 Managed[Scheduled]ExecutorService 例如:注册 ManagedTaskListener VALUE_NUMBER // Runnable implements ManagedTask public class TaskWithListener implements Runnable, ManagedTask {... public ManagedTaskListener getManagedTaskListener() { return aManagedTaskListener; } //use ManagedExecutors utility to associate a ManagedTaskListener to a task Runnable aTask; ManagedTaskListener myTaskListner; Runnable taskWithListener = ManagedExecutors.managedTask(aTask, myTaskListener);... ManagedExecutorService executor =...; executor.submit(task);
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 32 ManagedThreadFactory 应用程序从 Java EE 容器获取容器托管线程的标准方法 在 newThread 调用中捕获的容器上下文应用到调用 r.run() 的线 程中 在高级用例中创建定制执行器 预配置的默认值: – java:comp/DefaultManagedThreadFactory 概述
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 33 ManagedThreadFactory JNDI 名称 上下文信息 – 类加载器 – JNDI – 安全性 优先级 示例配置
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 34 ManagedThreadFactory 接口从 java.util.concurrent.ThreadFactory 扩展 – 相同 API : Thread newThread(Runnable) newThread() 方法返回的线程必须实现 ManagableThread 接口 – boolean isShutdown() 可与 Java SE 并发性实用程序 API 结合使用(需要 ThreadFactory 时)。例如,在 java.util.concurrent.Executors 中 API
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 35 ManagedThreadFactory ManagedThreadFactory 关闭时线程中断 中断时, Runnable 应检查 ManagableThread.isShutdown() , 如果为真应清理。 Shutdown
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 36 ManagedThreadFactory // Create a ThreadPoolExecutor using a ManagedThreadFactory tf; public ExecutorService getManagedThreadPool() { // All threads will run as part of this application component. return new ThreadPoolExecutor(5, 10, 5, TimeUnit.SECONDS, new ArrayBlockingQueue (10), tf); } 示例 1
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 37 ManagedThreadFactory public class TestServlet extends HttpServlet private ManagedThreadFactory managedThreadFactory; protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { final AsyncContext asyncContext = req.startAsync(); … Runnable runnable = new Runnable() { public void run() { … asyncContext.complete(); } }; Thread thread = managedThreadFactory.newThread(runnable); thread.start(); } } 示例 2 (采用 Servlet 异步模式)
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 38 ContextService 创建上下文代理对象并捕获容器上下文,以便稍后该代理对象在捕获 的上下文中运行 在高级用例中使用,例如传播用户身份或请求任务监听器通知以便在 容器上下文内运行 上下文代理对象还可用作提交到 Managed[Scheduled]ExecutorService 或 ManagedThreadFactory 的任务 预配置的默认值: – java:comp/DefaultContextService 概述
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 39 ContextService JNDI 名称 上下文信息 – 类加载器 – JNDI – 安全性 示例配置
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 40 ContextService 接口 创建动态代理(如同 java.lang.reflect.Proxy 中) 用其他上下文,例如,类加载、命名空间、安全性等 如果代理已经序列化,则实例必须实现可序列化 执行属性, Map – 保留键:以 “ javax.enterprise.concurrent” 开始 – 例如, vendor.security.tokenexpiration API
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 41 ContextService 四个 createContextualProxy 方法: – T createContextualProxy(T instance, Class intf) – T createContextualProxy(T instance, Map executionProperties, Class intf) – Object createContextualProxy(Object instance, Map executionProperties, Class...Interfaces) – Object createContextualProxy(Object instance, Class...Interfaces) API (续)
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 42 ContextService 在给定上下文对象代理实例上返回执行属性 – Map getExecutionProperties(Object contextualProxy) – IllegalArgumentException: if contextualProxy is not a valid proxy object created with #createContextualProxy of this ContextService API (续 2 )
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 43 ContextService 示例 ContextService ctxSvc; MyAppIntf proxy = ctxSvc.createContextualProxy (myAppImpl, MyAppIntf.class); // invoke at a later time, possibly in a different app // component proxy.doSomething();
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 44 ContextService // In application public interface MessageProcessor { public void processMessage(Message msg) … } // Within servlet or EJB ContextService ctxSvc; void businessMethod() { MessageProcessor msgProcessor = … // Wrap with the current context MessageProcessor proxy = ctxSvc.createContextualProxy (msgProcessor, MessageProcessor.class); // Store the contextual proxy object somewhere for running later. store.putIt(proxy); … 示例 2
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 45 ContextService // Elsewhere, in a different thread, retrieve the MessageProcessor contextual proxy // object from the store MessageProcessor proxy = store.getIt(); // The proxy method processMessage() is invoked on // this thread, but with the context of the servlet or // EJB that created it. proxy.processMessage(msg); 示例 2 (续)
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 46 ContextService // in Servlet A Callable mywork = contextService.createContextualProxy(new MyWork(), Callable.class); try (ObjectOutputStream oos = …) { oos.writeObject(mywork); } 示例 3 ( Web 应用程序中的序列化) // in Servlet B try (ObjectInputStream ois = …) { myWork = (Callable)ois.readObject(); managedExecutorService.submit(myWork); … public class MyWork implements Callable, Serializable { … }
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 47 议题 概述 托管对象 上下文和事务 总结 资源
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 48 上下文和事务 容器上下文的类型: – 类加载、 JNDI 命名空间、安全标识 – 可配置、可扩展 要在执行线程以及代理调用时上应用的捕获到的容器上下文 在全部 4 种类型的托管对象中均受支持 上下文传播
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 49 上下文和事务 事务通常不会传播到执行任务 来自 JTA 的 UserTransaction 可用 来自 ContextService 的上下文代理对象可在与调用线程相同 的事务上下文上运行 事务管理
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 50 private ContextService private UserTransaction ut; … ut.begin(); … MyWork proxy = cx.createContextualProxy(work, map, MyWork.class); … ut.commit(); 示例
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 51 议题 概述 托管对象 上下文和事务 总结 资源
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 52 总结 为 Java EE 应用程序组件提供异步功能 允许 Java SE 开发人员使用到 Java EE 的简单迁移路径 向应用程序提供托管对象,用于提交任务及获取托管线程 诸如容器上下文传播等特性 Java EE 应用程序开发人员现在拥有相关工具,可对异步处理进行更 高级的控制
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 53 议题 概述 托管对象 上下文和事务 总结 资源
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 54 资源 规范和 API 文档 – – Java EE 7 SDK – GlassFish 4.0 – 参考实现 –
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 55 Graphic Section Divider
版权所有 © 2013 , Oracle 和 / 或其关联公司。保留所有权利。 56