Google

Jan 30, 2014

Exposing a Java class as a MXBean

This Java tutorial extends Java ExecutorService for multi-threading -- coding question and tutorial by exposing it as an MXBean so that MXBean properties can be viewed and set via JConsole as demonstrated below.

Step 1:  The changes from the previous tutorial are

1. It implements SumEngineMXBean interface  with the naming convention suffix MXBean and the methods that needs to be exposed must be defined.
2. The thread pool size is managed via threadPoolSize variable and it needs to have getThreadPoolSize( ) and setThreadPoolSize(int threadPoolSize) methods to view and modify this variable JConsole, which is a JMX console to monitor your JVM.
3. The getRequestsCount( ) is also managed via JMX to view the requests counts via JConsole.

package com.mycompany.metrics;

import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicInteger;

public class SumEngine implements SumEngineMXBean{

private final AtomicInteger requestsCount = new AtomicInteger();

 private ExecutorService executionService = null;
 private int threadPoolSize = 1;

 //executes requests to sum
 public void execute(SumRequest... request) {
  executionService = Executors.newFixedThreadPool(threadPoolSize); //create a thread pool
  List<Callable<SumResponse>> tasks = createExecuteTasks(request);
  List<Future<SumResponse>> results = execute(tasks);
  for (Future<SumResponse> result : results) {

   try {
    System.out.println(Thread.currentThread().getName() + ": Response = " + result.get());
   } catch (InterruptedException e) {
    e.printStackTrace();
   } catch (ExecutionException e) {
    e.printStackTrace();
   }
  }
  
  //initiates an orderly shutdown of thread pool
  executionService.shutdown();
 }

 //create tasks
 private List<Callable<SumResponse>> createExecuteTasks(SumRequest[] requests) {
  List<Callable<SumResponse>> tasks = new LinkedList<Callable<SumResponse>>();
  executingRequests(requests.length);
  for (SumRequest req : requests) {
   Callable<SumResponse> task = createTask(req);
   tasks.add(task);
  }

  return tasks;
 }

 //increment the requests counter
 private void executingRequests(int count) {
  requestsCount.addAndGet(count);
 }

 //creates callable (i.e executable or runnable tasks) 
 private Callable<SumResponse> createTask(final SumRequest request) {
  // anonymous implementation of Callable.
  // Pre Java 8's way of creating closures
  Callable<SumResponse> task = new Callable<SumResponse>() {

   @Override
   public SumResponse call() throws Exception {
    System.out.println(Thread.currentThread().getName() + ": Request = " + request);
    SumProcessor<SumRequest, SumResponse> processor = new SumProcessorImpl<>();
    SumResponse result = processor.sum(request);
    return result;
   }

  };

  return task;
 }

 //executes the tasks
 private <T> List<Future<T>> execute(List<Callable<T>> tasks) {

  List<Future<T>> result = null;
  try {
   //invokes the sum(sumRequest) method by executing the closure call() inside createTask
   result = executionService.invokeAll(tasks);
  } catch (InterruptedException e) {
   e.printStackTrace();
  }

  return result;

 }
 
 
 public int getRequestsCount(){
  return requestsCount.get();
 }
 
 

 public int getThreadPoolSize() {
  return threadPoolSize;
 }

 @Override
 public void setThreadPoolSize(int threadPoolSize) {
  this.threadPoolSize = threadPoolSize;
 } 
}


Step 2: The test class SumEngineTest that runs forever in an endless while loop. This allows you to monitor your app via JConsole as it runs. For example, change the threadPoolSize and view both the threadPoolSize  and  requestsCount. THe MBean server lines are also added to register the MXBean.

package com.mycompany.metrics;

import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import javax.management.MBeanServer;
import javax.management.ObjectName;

public class SumEngineTest {

 public static void main(String[] args) throws Exception {

  SumEngine se = new SumEngine();
  
  //Register with MBeanServer
  MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
  ObjectName name = new ObjectName("com.mycompany.metrics:type=SumEngine");
  mbs.registerMBean(se, name);

  List<SumRequest> list = new ArrayList<>();

  //run for ever
  while (true) {

   // sums 1+2, 2+3, 3+4, etc
   for (int i = 1; i <= 5; i++) {
    SumRequest req = new SumRequest();
    req.setOperand1(i);
    req.setOperand2(i + 1);
    list.add(req);
   }

   SumRequest[] req = new SumRequest[list.size()];
   se.execute((SumRequest[]) list.toArray(req));
   
   // sleep for 5 seconds
   TimeUnit.SECONDS.sleep(5); 
   list.clear();
  }

 }

}

Step 3: Run the SumEngineTest, and  wherever the engine is running,   go to the DOS command prompt and type jconsole. This pops up the jconsole GUI. Connect to com.mycompany.metrics.SumEngineTest.





You can try increase the threadPoolSize and check the output to see if more threads are used.  Also, look at the other tabs memory, threads, overview, etc.

Labels:

0 Comments:

Post a Comment

Subscribe to Post Comments [Atom]

<< Home