Slide 1

Slide 1 text

@goldstift #DV14 #jsr236 Concurrency in Enterprise Java Alexander Heusingfeld

Slide 2

Slide 2 text

— Junior programmers think concurrency is hard. Experienced programmers think concurrency is easy. Senior programmers think concurrency is hard. Unknown @goldstift #dv14 #jsr236

Slide 3

Slide 3 text

There ain’t no fuzz about this, right? @goldstift #dv14 #jsr236

Slide 4

Slide 4 text

Runnable myRunnable = new Runnable() { public void run() { // do stuff in Thread } }; Thread myThread = new Thread(myRunnable); myThread.start(); // ...and off we go! @goldstift #dv14 #jsr236

Slide 5

Slide 5 text

Nooooooo! http://www.flickr.com/photos/girlaphid/3818224024/sizes/l/

Slide 6

Slide 6 text

1. No management of Thread lifecycle 2. No management of number of Threads 3. Monitoring tedious/ almost impossible 4. No propagation of context

Slide 7

Slide 7 text

*sigh* Got alternatives? http://www.flickr.com/photos/spanishflea/215064063/sizes/o/

Slide 8

Slide 8 text

> java.util.concurrent?! @goldstift #dv14 #jsr236

Slide 9

Slide 9 text

ExecutorServices > Executors.newSingleThreadExecutor() > Executors.newCachedThreadPool() > Executors.newFixedThreadPool() > Executors.newScheduledThreadPool() @goldstift #dv14 #jsr236

Slide 10

Slide 10 text

> JSR236 > javax.enterprise.concurrent @goldstift #dv14 #jsr236

Slide 11

Slide 11 text

Why should I be interested? @goldstift #dv14 #jsr236

Slide 12

Slide 12 text

Patterns of software stability

Slide 13

Slide 13 text

Patterns of software stability > Timeouts - executor timeouts provide fallbacks

Slide 14

Slide 14 text

Patterns of software stability > Timeouts - executor timeouts provide fallbacks > Bulkheads - separate your application components

Slide 15

Slide 15 text

Patterns of software stability > Timeouts - executor timeouts provide fallbacks > Bulkheads - separate your application components > Circuit Breaker - fail-fast if no threads available

Slide 16

Slide 16 text

Patterns of software stability > Timeouts - executor timeouts provide fallbacks > Bulkheads - separate your application components > Circuit Breaker - fail-fast if no threads available > Steady State - free unused resources

Slide 17

Slide 17 text

Patterns of software stability > Timeouts - executor timeouts provide fallbacks > Bulkheads - separate your application components > Circuit Breaker - fail-fast if no threads available > Steady State - free unused resources http://michaelnygard.com/

Slide 18

Slide 18 text

What’s in it for the devs? @goldstift #dv14 #jsr236

Slide 19

Slide 19 text

ManagedThreadFactory

Slide 20

Slide 20 text

ManagedThreadFactory > extends the Java SE ThreadFactory > same API as Thread.newThread(Runnable) > Threads returned implement ManageableThread > Enables use of Java SE concurrency utilities like Executors @goldstift #dv14 #jsr236

Slide 21

Slide 21 text

ExecutorServices for Java EE Executors.newSingleThreadExecutor(ThreadFactory) Executors.newCachedThreadPool(ThreadFactory) Executors.newFixedThreadPool(int, ThreadFactory) Executors.newScheduledThreadPool(int, ThreadFactory) @goldstift #dv14 #jsr236

Slide 22

Slide 22 text

@Resource ManagedThreadFactory factory; protected void processRequest(ServiceRequestData data) { // Creating Java SE style ExecutorService ExecutorService executor = Executors.newFixedThreadPool(10, factory); Future f = executor.submit(new MyTask(data)); } @goldstift #dv14 #jsr236

Slide 23

Slide 23 text

1 public class MyTask implements Runnable { 2 public void run() { 3 InitialContext ctx = null; 4 try { 5 ctx = new InitialContext(); 6 UserTransaction ut = (UserTransaction) ctx.lookup( 7 "java:comp/UserTransaction"); 8 ut.begin(); 9 while (!((ManageableThread) Thread.currentThread()).isShutdown()){ 10 11 // Perform transactional business logic? 12 } 13 // do cleanup 14 ut.commit(); 15 } catch (Exception ex) { 16 ex.printStackTrace(); 17 } 18 } 19 } @goldstift #dv14 #jsr236

Slide 24

Slide 24 text

ManagedExecutorService

Slide 25

Slide 25 text

ManagedExecutorService extends the Java SE ExecutorService methods for submitting tasks to Java EE environment available via JNDI look-up or @Resource injection Tasks must implement Runnable or Callable Lifecycle APIs disabled -> throw IllegalStateException @goldstift #dv14 #jsr236

Slide 26

Slide 26 text

1 @Resource ManagedExecutorService mes; 2 3 protected String processRequest(ServiceRequest request) { 4 Future f = mes.submit(new Callable() { 5 public String call() { 6 // do something with context 7 return "result"; 8 } 9 }); 10 try { 11 return f.get(); 12 } catch (InterruptedException | ExecutionException ex) { 13 throw new IllegalStateException("Cannot get the answer", ex); 14 } 15 } @goldstift #dv14 #jsr236

Slide 27

Slide 27 text

1 @Resource ManagedExecutorService mes; 2 3 class MyLongReturningTask implements Callable { . . . } 4 class MyDateReturningTask implements Callable { . . . } 5 6 protected void processRequest(ServiceRequest request) throws 7 ExecutionException { 8 9 ArrayList tasks = new ArrayList<(); 10 tasks.add(new MyLongReturningTask()); 11 tasks.add(new MyDateReturningTask()); 12 List> result = executor.invokeAll(tasks); 13 } @goldstift #dv14 #jsr236

Slide 28

Slide 28 text

1 @WebServlet(urlPatterns = "/MyAsyncServlet", asyncSupported = true) 2 public class MyAsyncServlet extends HttpServlet { 3 4 @Resource ManagedExecutorService executor; 5 6 protected void doGet(HttpServletRequest request, HttpServletResponse 7 response) throws ServletException, IOException { 8 9 final AsyncContext ac = request.startAsync(); 10 Runnable task = new Runnable() { 11 public void run() { 12 // ... evaluate result 13 ac.getResponse().getWriter().print(result); 14 ac.complete(); 15 } 16 } 17 executor.submit(task); 18 } 19 } @goldstift #dv14 #jsr236

Slide 29

Slide 29 text

ManagedScheduledExecutorService

Slide 30

Slide 30 text

ManagedScheduledExecutorService > extends ManagedExecutorService > extends ScheduledExecutorService > additional methods to schedule tasks with new Trigger > new methods also return ScheduledFuture objects @goldstift #dv14 #jsr236

Slide 31

Slide 31 text

@Resource ManagedScheduledExecutorService executor; protected void processRequest(ServiceRequest request) { ScheduledFuture f = executor.scheduleAtFixedRate( new MyRunnableTask(request), 5, 10, TimeUnit.SECONDS); } @goldstift #dv14 #jsr236

Slide 32

Slide 32 text

1 public class MyTrigger implements Trigger { 2 3 private final Date firetime; 4 5 public MyTrigger(Date firetime) { this.firetime = firetime; } 6 7 @Override 8 public Date getNextRunTime(LastExecution le, Date taskScheduledTime) { 9 if (firetime.before(taskScheduledTime)) { 10 return null; 11 } 12 return firetime; 13 } 14 15 @Override 16 public boolean skipRun(LastExecution le, Date scheduledRunTime) { 17 return firetime.before(scheduledRunTime); 18 } 19 } @goldstift #dv14 #jsr236

Slide 33

Slide 33 text

ContextService

Slide 34

Slide 34 text

ContextService > creating contextual proxies > Examples of context: persistence, EJBs, security > customisable through ExecutionProperties > Can be run on transaction context of invoking thread (if any) @goldstift #dv14 #jsr236

Slide 35

Slide 35 text

1 // within servlet or EJB method 2 @Resource ContextService service; 3 4 // Capture application context for later execution 5 IMessageProcessor processor = ...; 6 IMessageProcessor proxy = service.createContextualProxy(processor, 7 IMessageProcessor.class); 8 cache.put(IMessageProcessor.class, proxy); 12 // at a later time in a different thread retrieve the proxy from the cache 13 IMessageProcessor worker = cache.get(IMessageProcessor.class); 14 // and execute with the context of the servlet or EJB 15 worker.processMessage(msg); @goldstift #dv14 #jsr236

Slide 36

Slide 36 text

ManagedTaskListener void taskSubmitted(java.util.concurrent.Future future, ManagedExecutorService executor, Object task) void taskStarting(java.util.concurrent.Future future, ManagedExecutorService executor, Object task) void taskAborted(java.util.concurrent.Future future, ManagedExecutorService executor, Object task, java.lang. Throwable exception) void taskDone(java.util.concurrent.Future future, ManagedExecutorService executor, Object task, java.lang.Throwable exception) @goldstift #dv14 #jsr236

Slide 37

Slide 37 text

ManagedExecutors class // Register listener for task with specific executionProperties. // Adopts executionProperties of ManageableTask Runnable managedTask(Runnable, ManagedTaskListener) Runnable managedTask(Runnable, Map,
 ManagedTaskListener) Callable managedTask(Callable, ManagedTaskListener) Callable managedTask(Callable, Map, 
 ManagedTaskListener) // Checks “currentThread instanceof ManageableThread” ManagedExecutors.isCurrentThreadShutdown()

Slide 38

Slide 38 text

DevOps: How do we do it? @goldstift #dv14 #jsr236

Slide 39

Slide 39 text

Setup - CLI $JBOSS_HOME/bin/jboss-cli.sh —connect “/subsystem=ee/managed-executor- service=async-http-mes/:add(
 core-threads=20,
 jndi-name=java:comp/async-http-mes,
 context-service=default,
 hung-task-threshold=110000,
 keepalive-time=60000,
 thread-factory=default,
 queue-length=50,
 reject-policy=ABORT,
 max-threads=500)” @goldstift #dv14 #jsr236

Slide 40

Slide 40 text

WildFly CLI - Monitoring $JBOSS_HOME/bin/jboss-cli.sh --connect "/subsystem=ee/managed-executor- service=async-http-mes/:read-resource(recursive-depth=0,include-runtime=true)" {
 "outcome" => "success",
 "result" => {
 "context-service" => "default",
 "core-threads" => 20,
 "hung-task-threshold" => 110000L,
 "jndi-name" => "java:jboss/ee/concurrency/executor/async-http-mes",
 "keepalive-time" => 60000L,
 "long-running-tasks" => false,
 "max-threads" => 500,
 "queue-length" => 50,
 "reject-policy" => "ABORT",
 "thread-factory" => "default"
 }
 } @goldstift #dv14 #jsr236

Slide 41

Slide 41 text

Too complicated? @goldstift #dv14 #jsr236

Slide 42

Slide 42 text

Wildfly CLI command WildFly CLI comes with a command builder gui: $JBOSS_HOME/bin/jboss-cli.sh --gui @goldstift #dv14 #jsr236

Slide 43

Slide 43 text

Wildfly CLI command WildFly CLI comes with a command builder gui: $JBOSS_HOME/bin/jboss-cli.sh --gui @goldstift #dv14 #jsr236

Slide 44

Slide 44 text

Still too complicated? @goldstift #dv14 #jsr236

Slide 45

Slide 45 text

Management & Monitoring > Everything published as JMX MBeans > -> values > -> operations > -> metadata @goldstift #dv14 #jsr236

Slide 46

Slide 46 text

Ok, are we fine? @goldstift #dv14 #jsr236

Slide 47

Slide 47 text

Gotcha!! http://www.flickr.com/photos/upturnedface/2700127506/sizes/o/

Slide 48

Slide 48 text

1. The single ExecutorService

Slide 49

Slide 49 text

@Resource ManagedExecutorService mes;
 
 protected void processRequest(ServiceRequest request) throws
 ExecutionException {
 Future f = mes.submit(new Callable() {...});
 System.out.println(“Callable result: “ + f.get()); } @goldstift #dv14 #jsr236

Slide 50

Slide 50 text

@Resource ManagedExecutorService mes;
 
 protected void processRequest(ServiceRequest request) throws
 ExecutionException {
 Future f = mes.submit(new Callable() {...});
 System.out.println(“Callable result: “ + f.get()); } @goldstift #dv14 #jsr236 Only used here??

Slide 51

Slide 51 text

@Resource ManagedExecutorService mes;
 
 protected void processRequest(ServiceRequest request) throws
 ExecutionException {
 Future f = mes.submit(new Callable() {...});
 System.out.println(“Callable result: “ + f.get()); } @goldstift #dv14 #jsr236 Only used here?? @Resource(lookup=“java:comp/service-request-executor“)

Slide 52

Slide 52 text

2. The queue that queued

Slide 53

Slide 53 text

@Resource ManagedThreadFactory factory;
 
 protected void processRequest(ServiceRequestData data) {
 
 // Creating Java SE style ExecutorService
 BlockingQueue queue = new LinkedBlockingQueue(10);
 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10,
 0L, TimeUnit.MILLISECONDS,
 queue, 
 factory); 
 // MyRunnable has to implement .equals() and .hashcode()!!!
 MyRunnable task = new MyRunnable(data);
 
 // prevent duplicate queue entries
 if (!queue.contains(task)) {
 executor.submit(task);
 }
 } @goldstift #dv14 #jsr236

Slide 54

Slide 54 text

@Resource ManagedThreadFactory factory;
 
 protected void processRequest(ServiceRequestData data) {
 
 // Creating Java SE style ExecutorService
 BlockingQueue queue = new LinkedBlockingQueue(10);
 ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10,
 0L, TimeUnit.MILLISECONDS,
 queue, 
 factory); 
 // MyRunnable has to implement .equals() and .hashcode()!!!
 MyRunnable task = new MyRunnable(data);
 
 // prevent duplicate queue entries
 if (!queue.contains(task)) {
 executor.submit(task);
 }
 } @goldstift #dv14 #jsr236 .contains() locks queue!

Slide 55

Slide 55 text

3. A self overtaking job

Slide 56

Slide 56 text

@Resource ManagedScheduledExecutorService executor;
 
 protected void processRequest(ServiceRequest job) {
 ScheduledFuture f = executor.scheduleAtFixedRate(
 new MyRunnableTask(job), 5, 10, TimeUnit.SECONDS);
 
 }
 @goldstift #dv14 #jsr236

Slide 57

Slide 57 text

4. Know your RejectionPolicy

Slide 58

Slide 58 text

@goldstift #dv14 #jsr236 Competition from Spring

Slide 59

Slide 59 text

@goldstift #dv14 #jsr236 Competition from Spring ManagedExecutors can only ABORT

Slide 60

Slide 60 text

5. Go Java 8 and shine

Slide 61

Slide 61 text

WildFly compatible with Java 8 @goldstift #dv14 #jsr236

Slide 62

Slide 62 text

WildFly compatible with Java 8 Possibility to combine executors with @goldstift #dv14 #jsr236

Slide 63

Slide 63 text

WildFly compatible with Java 8 Possibility to combine executors with -> Lambdas @goldstift #dv14 #jsr236

Slide 64

Slide 64 text

WildFly compatible with Java 8 Possibility to combine executors with -> Lambdas -> Streams @goldstift #dv14 #jsr236

Slide 65

Slide 65 text

WildFly compatible with Java 8 Possibility to combine executors with -> Lambdas -> Streams -> CompletableFuture @goldstift #dv14 #jsr236

Slide 66

Slide 66 text

WildFly compatible with Java 8 Possibility to combine executors with -> Lambdas -> Streams -> CompletableFuture @goldstift #dv14 #jsr236

Slide 67

Slide 67 text

WildFly compatible with Java 8 Possibility to combine executors with -> Lambdas -> Streams -> CompletableFuture Are you sure?? @goldstift #dv14 #jsr236

Slide 68

Slide 68 text

Java 8 Streams API @goldstift #dv14 #jsr236

Slide 69

Slide 69 text

Java 8 Streams API final List products = productUris.parallelStream()
 .map(productUri -> CompletableFuture.supplyAsync(() -> resolveProducts(productUri)))
 .map(CompletableFuture::join)
 .filter(res -> res.second.hasBody())
 .map(this::responsePairToProduct)
 .collect(Collectors.toList()); @goldstift #dv14 #jsr236

Slide 70

Slide 70 text

Java 8 Streams API final List products = productUris.parallelStream()
 .map(productUri -> CompletableFuture.supplyAsync(() -> resolveProducts(productUri)))
 .map(CompletableFuture::join)
 .filter(res -> res.second.hasBody())
 .map(this::responsePairToProduct)
 .collect(Collectors.toList()); ForkJoinPool @goldstift #dv14 #jsr236

Slide 71

Slide 71 text

Java 8 Streams API final List products = productUris.parallelStream()
 .map(productUri -> CompletableFuture.supplyAsync(() -> resolveProducts(productUri)))
 .map(CompletableFuture::join)
 .filter(res -> res.second.hasBody())
 .map(this::responsePairToProduct)
 .collect(Collectors.toList()); ForkJoinPool incompatible with ManagedThreads @goldstift #dv14 #jsr236

Slide 72

Slide 72 text

Java 8 Streams API final List products = productUris.parallelStream()
 .map(productUri -> CompletableFuture.supplyAsync(() -> resolveProducts(productUri)))
 .map(CompletableFuture::join)
 .filter(res -> res.second.hasBody())
 .map(this::responsePairToProduct)
 .collect(Collectors.toList()); ForkJoinPool incompatible with ManagedThreads Cannot recommend to use parallel Streams API in Java EE! @goldstift #dv14 #jsr236

Slide 73

Slide 73 text

No Java 8? Try Guava! https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained @goldstift #dv14 #jsr236

Slide 74

Slide 74 text

No Java 8? Try Guava! https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained @goldstift #dv14 #jsr236 @Resource(name = "BackendCallExecutorService")
 ManagedExecutorService executor;


Slide 75

Slide 75 text

No Java 8? Try Guava! https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained @goldstift #dv14 #jsr236 @Resource(name = "BackendCallExecutorService")
 ManagedExecutorService executor;
 final String productId = ...;
 ListeningExecutorService service = MoreExecutors.listeningDecorator(executor);

Slide 76

Slide 76 text

No Java 8? Try Guava! https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained @goldstift #dv14 #jsr236 @Resource(name = "BackendCallExecutorService")
 ManagedExecutorService executor;
 final String productId = ...;
 ListeningExecutorService service = MoreExecutors.listeningDecorator(executor); 
 ListenableFuture product = service.submit(new Callable() {
 public Product call() {
 return resolveProduct(productId);
 }
 });


Slide 77

Slide 77 text

No Java 8? Try Guava! https://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained @goldstift #dv14 #jsr236 @Resource(name = "BackendCallExecutorService")
 ManagedExecutorService executor;
 final String productId = ...;
 ListeningExecutorService service = MoreExecutors.listeningDecorator(executor); 
 ListenableFuture product = service.submit(new Callable() {
 public Product call() {
 return resolveProduct(productId);
 }
 });
 Futures.addCallback(explosion, new FutureCallback() {
 public void onSuccess(Product product) {
 addProductToCart(product);
 }
 public void onFailure(Throwable thrown) { 
 offerFallbackProduct(); // business decision!!
 }
 });

Slide 78

Slide 78 text

Anything else? http://www.flickr.com/photos/weaselmcfee/3721267658/sizes/o/

Slide 79

Slide 79 text

sounds familiar? @goldstift #dv14 #jsr236

Slide 80

Slide 80 text

sounds familiar? > Yes! Xebia came up with something alike for Spring in 2011 @goldstift #dv14 #jsr236

Slide 81

Slide 81 text

sounds familiar? > Yes! Xebia came up with something alike for Spring in 2011 async-http-mes/:add(
 core-threads=20,
 jndi-name=java:comp/async-http-mes,
 context-service=default,
 hung-task-threshold=110000,
 keepalive-time=60000,
 thread-factory=default,
 queue-length=50,
 reject-policy=ABORT,
 max-threads=500) WildFly @goldstift #dv14 #jsr236

Slide 82

Slide 82 text

sounds familiar? https://code.google.com/p/xebia-france/wiki/XebiaManagementExtras @goldstift #dv14 #jsr236

Slide 83

Slide 83 text

sounds familiar? https://code.google.com/p/xebia-france/wiki/XebiaManagementExtras > Yes! Xebia came up with something alike for Spring in 2011 @goldstift #dv14 #jsr236

Slide 84

Slide 84 text

A note on Hystrix > Netflix Hystrix is a well-known implementation of the stability patterns - especially Circuit-Breaker > Hystrix in Java EE is no free lunch > set env var 
 “-Dhystrix.plugin.HystrixConcurrencyStrategy.implementation=\
 full.package.of.MyConcurrencyStrategy” @goldstift #dv14 #jsr236

Slide 85

Slide 85 text

Spring 4.0 supports JSR236 Provides configurability & monitoring via JSR236 -> ConcurrentTaskExecutor auto-detects JSR236 classes -> Uses specified ManagedExecutor transparently -> executor manageable via CLI or JMX -> Check the code, it’s open-source! @Github #4004e53 @goldstift #dv14 #jsr236

Slide 86

Slide 86 text

Summary > good mix of convenience & flexibility > still potential for optimisation: > API to create ManagedExecutorService instead of defaults > validation/ constraints for ManagedExecutorService properties > Runtime.availableProcessors() for parallelism is deceptive!!! > Please become compatible with ForkJoinPool/ JDK8 Streams API @goldstift #dv14 #jsr236

Slide 87

Slide 87 text

Links JSR236 spec: https://jcp.org/en/jsr/detail?id=236 Java EE 7 JavaDoc: http://docs.oracle.com/javaee/7/api/ Java EE 7 samples: https://github.com/javaee-samples/javaee7-samples Wildfly docs: https://docs.jboss.org/author/display/WFLY8/EE+Subsystem+Configuration @goldstift #dv14 #jsr236

Slide 88

Slide 88 text

Thanks for your attention! Alexander Heusingfeld, @goldstift [email protected] https://www.innoq.com/people/alex/ @goldstift #dv14 #jsr236