Doing this exercise, participants will learn:
-
what are the "Concurrency Utilities for Java EE 1.0"
-
how to use the the Java Concurrency API
-
how to configure the concurrency services on JBoss EAP 7
Concurrency is the ability of a system to execute several tasks in parallel, during overlapping time periods, instead of sequentially. The "Concurrency Utilities for Java EE 1.0" (JSR342) specification was developed to fulfill the following goals:
-
provide a simple/flexible/usable API for implementing simple and advanced concurrency patterns
-
facilitate the migration from Java SE and EE
It has been built on top of the "Concurrency Utilities API" for Java SE (JSR166). The Java SE specification has been made Java EE aware by getting capabilities like container context propagation, transaction management and task events notification. Thanks to this API, Java EE 7 platforms are aware of the resources used by threads and capable of managing their pools and life-cycles properly.
The API provides thread pools and executor with 4 managed object types in the javax.enterprise.concurrent
package:
-
Context (
javax.enterprise.concurrent.ContextService
)The Context Service is a concurrency utility which creates contextual proxies from existent objects. JBoss EAP 7 Context Services are also used to propagate the context from a Java EE application invocation thread, to the threads internally used by the other EE Concurrency Utilities. Context Service instances may be created using the subsystem XML configuration:
<context-services> <context-service name="default" jndi-name="java:jboss/ee/concurrency/context/default" use-transaction-setup-provider="true" /> </context-services>
-
Thread Factory (
javax.enterprise.concurrent.ManagedThreadFactory
)The Managed Thread Factory allows Java EE applications to create new threads. The Managed Thread Factory instances may also, optionally, use a Context Service instance to propagate the Java EE application thread’s context to the new threads. Instance creation is done through the EE subsystem, by editing the subsystem XML configuration:
<managed-thread-factories> <managed-thread-factory name="default" jndi-name="java:jboss/ee/concurrency/factory/default" context-service="default" priority="1" /> </managed-thread-factories>
-
Executor (
javax.enterprise.concurrent.ManagedExecutorService
)The Managed Executor Service is the Java EE adaptation of Java SE Executor Service, providing to Java EE applications the functionality of asynchronous task execution. JBoss EAP 7 is responsible to manage the lifecycle of Managed Executor Service instances, which are specified through the EE subsystem XML configuration:
<managed-executor-services> <managed-executor-service name="default" jndi-name="java:jboss/ee/concurrency/executor/default" context-service="default" thread-factory="default" hung-task-threshold="60000" core-threads="5" max-threads="25" keepalive-time="5000" queue-length="1000000" reject-policy="RETRY_ABORT" /> </managed-executor-services>
-
Scheduled Executor (
javax.enterprise.concurrent.ManagedScheduledExecutorService
)The Managed Scheduled Executor Service is the Java EE adaptation of Java SE Scheduled Executor Service, providing to Java EE applications the functionality of scheduling task execution. JBoss EAP 7 is responsible to manage the lifecycle of Managed Scheduled Executor Service instances, which are specified through the EE subsystem XML configuration:
<managed-scheduled-executor-services> <managed-scheduled-executor-service name="default" jndi-name="java:jboss/ee/concurrency/scheduler/default" context-service="default" thread-factory="default" hung-task-threshold="60000" core-threads="5" keepalive-time="5000" reject-policy="RETRY_ABORT" /> </managed-scheduled-executor-services>
In addition to these main interfaces, the specification provides many other interfaces, for example to monitor the stat of a task’s Future object (ManagedTaskListener
).
This lab builds on the "managed-executor-service" quickstart of JBoss EAP 7. It demonstrates how Java EE applications can submit tasks for asynchronous execution.
- Step 1 - Build the "managed-executor-service" quickstart project
-
First build the managed-executor-service project as follows:
$ cd ~/exercises/projects/05_concurrency/managed-executor-service # (1) $ mvn clean eclipse:clean eclipse:eclipse install # (2) $ pwd (3)
-
Move to the directory of the quickstart
-
Clean and build the quickstart and generate the eclipse project
-
Displays the current path (useful for import in JBDS)
-
- Step 2 - Import the project in JBoss Developer Studio (JBDS)
-
Open JBoss Developer Studio (desktop shortcut).
Import the maven project you just built. (File → Import → Existing Projects into Workspace → Next → Paste "root directory") → Finish)
- Step 3 - Have a look at the Java code
-
The imported application contains a JAX-RS resource (
ProductResourceRESTService
class) providing access to several operations that are executed asynchronously:PersitTask
,LongRunningTask
andDeleteTask
.Take some time to understand how these classes inter-relate and how the
ManagedExecutorService
is used.A test class (
ProductsRestClientTest
) has been defined to invoke the exposed REST methods and execute the defined tasks. In the next step, we are going to execute this test class. - Step 4 - Start JBoss EAP 7 and deploy the application
-
Start your JBoss EAP 7 server as described in the first lab.
You have two options for deploying the "jboss-managed-executor-service.war" binary:
-
Option 1: maven
Type this command to build and deploy the application:
$ mvn clean install wildfly:deploy
-
Option 2: JBDS
Right click on "/managed-executor-service/target/jboss-managed-executor-service.war" and select "Mark as Deployable"
-
- Step 5 - Run the tests
-
This quickstart provides tests that shows how the asynchronous tasks are executed. By default, these tests are configured to be skipped as the tests requires that the application to be deployed first.
You have two choices for executing the test:
-
Option 1: use maven
$ mvn clean test -Prest-test
-
Option 2: use JBDS
Right click on the project or individual classes and select Run As → JUnit Test in the context menu.
-
- Step 6 - Investigate the results
-
Review the JBoss EAR 7 console log output and relate it to the code. You should see log messages like the following:
13:34:07,940 INFO [ProductResourceRESTService] (default task-51) Will create a new Product on other Thread 13:34:07,940 INFO [ProductResourceRESTService] (default task-51) Returning response 13:34:07,941 INFO [PersitTask] (EE-ManagedExecutorService-default-Thread-5) Begin transaction 13:34:07,941 INFO [PersitTask] (EE-ManagedExecutorService-default-Thread-5) Persisting a new product 13:34:07,946 INFO [PersitTask] (EE-ManagedExecutorService-default-Thread-5) Commit transaction 13:34:08,002 INFO [ProductResourceRESTService] (default task-52) Submitting a new long running task to be executed 13:34:08,003 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:08,009 INFO [LongRunningTask] (EE-ManagedExecutorService-default-Thread-5) Starting a long running task 13:34:08,010 INFO [LongRunningTask] (EE-ManagedExecutorService-default-Thread-5) Analysing A Product 13:34:08,306 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:08,608 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:08,912 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:09,215 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:09,519 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:09,823 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:10,128 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:10,431 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:10,735 INFO [ProductResourceRESTService] (default task-52) Waiting for the result to be available... 13:34:11,040 INFO [ProductResourceRESTService] (default task-52) Result is available. Returning result...56 13:34:11,082 INFO [ProductResourceRESTService] (default task-53) Will delete all Products on other Thread 13:34:11,082 INFO [ProductResourceRESTService] (default task-53) Returning response 13:34:11,082 INFO [DeleteTask] (EE-ManagedExecutorService-default-Thread-5) Begin transaction 13:34:11,083 INFO [DeleteTask] (EE-ManagedExecutorService-default-Thread-5) Deleting all products 13:34:11,092 INFO [DeleteTask] (EE-ManagedExecutorService-default-Thread-5) Commit transaction. Products deleted: 1
- Step 7 - Monitor the thread pools
-
In order to have a look at how the thread pools are managed, we will use the
jconsole
utility. To do so, open a Terminal and type:$ cd $JBOSS_HOME/bin $ ./jconsole.sh
A modal window will open, offering you to select various processes. Select the local process having a name starting with "jboss-modules.jar" and click on "connect".
A pop-up asking you if an insecure connection should be used is then displayed. Click on "Insecure connection".
Then you will see the threads used and consumed by the JBoss EAP 7:
- Step 8 - Increase the load
-
Now it is time to increase the load and send a lot of requests showing how the ManagedExecutorService behaves.
Find your preferred way to run many times the defined long-running task in parallel. Use then jconsole, as presented in step 7, to have a look on how the thread pool is behaving.
For example, you could add a test method like the following one and re-run the test:
@Test public void parallelTest() throws InterruptedException { Callable<String> c = () -> ClientBuilder.newClient().target(REST_TARGET_URL + "/longrunningtask").request().get(String.class); List<Callable<String>> callables = new ArrayList<Callable<String>>(); for (int i = 0; i < 100; i++) { callables.add(c); } Executors.newWorkStealingPool().invokeAll(callables).stream().map(future -> { try { return future.get(); } catch (Exception e) { throw new IllegalStateException(e); } }).forEach(System.out::println); }
- Step 9 - Review the EE concurrency configuration
-
The "Thread" subsystem of JBoss EAP 6 has been removed. All JBoss EAP 7 subsystems needing threads define their own thread pool. The Java EE concurrency utilities is configured within the "EE" subsystem of JBoss EAP 7.
The configuration can be viewed and modified in the JBoss EAP 7 management console over Configuration → Subsystems → EE, clicking on "View".
After selecting the "Services" tab, you are able to view and modify the configuration of the four previously listed concurrency services.
Another option to view and modify the configuration is to edit the standalone.xml file (while the server is stopped) or execute CLI commands.
In this lab, you learned what are the EE concurrency utilities and how they can be configured within JBoss EAP 7. You deployed and reviewed an application using the Java Concurrency API and monitored the behavior of the application platform using jconsole.
For more information, please have a look at the following articles and documents: