Monthly Archives: August 2012

Java-EE-compatible AbstractExecutorService Implementation (Part 2)

Here is another take on my previous post—this time using a @Singleton EJB with bean-managed concurrency.  First, I introduce a valid interface, but one which is essentially identical to Executor, with the added restriction that execution must be asynchronous (while this is a common thing for “regular” Executors to do, it is not strictly speaking required of them).  I do this for the essential bits of @Asynchronous dispatching (once you see that code below you’ll see why).  While you could certainly use this as a business interface, I wouldn’t really expect you to.  Here’s the AsynchronousExecutor interface:

public interface AsynchronousExecutor {
  public void executeAsynchronously(final Runnable runnable);
}
And now the re-done ExecutorServiceBean:

@ConcurrencyManagement(ConcurrencyManagementType.BEAN)
@Local({Executor.class, ExecutorService.class, AsynchronousExecutor.class})
@Singleton
public class ExecutorServiceBean extends AbstractExecutorService implements ExecutorService, AsynchronousExecutor {

  @Resource
  private SessionContext sessionContext;

  @Override
  public void execute(final Runnable runnable) {
    if (runnable != null) {
      if (this.sessionContext != null) {
        final AsynchronousExecutor self = this.sessionContext.getBusinessObject(AsynchronousExecutor.class);
        assert self != null;
        self.executeAsynchronously(runnable);
      } else {
        runnable.run();
      }
    }
  }

  @Asynchronous
  @Override
  public void executeAsynchronously(final Runnable runnable) {
    if (runnable != null) {
      runnable.run();
    }
  }

  @Override
  public boolean awaitTermination(final long timeout, final TimeUnit unit) {
    return false;
  }

  @Override
  public boolean isTerminated() {
    return false;
  }

  @Override
  public boolean isShutdown() {
    return false;
  }

  @Override
  public void shutdown() {

  }

  @Override
  public List<Runnable> shutdownNow() {
    return Collections.emptyList();
  }

}

I made a couple of changes:
  • First, I took advantage of the fact that
    AbstractExecutorService actually arranges all the work for you such that really all you have to override is the Executor#execute(Runnable) method.  Specifically, I no longer override the AbstractExecutorService#submit(Callable) method.
  • Second, I made sure that the invocation of the execute(Runnable) method is not itself declared to be @Asynchronous, but delegates this call to the executeAsynchronously(Runnable) method, which is declared to be @Asynchronous.  This is because the innards of the AbstractExecutorService class call the execute(Runnable) method directly.  Since the asynchronous behavior of an @Asynchronous-annotated method can only be accomplished if the control flow progresses through the container, this cumbersome construct is necessary.  One big assumption I made here is that access to the SessionContext object is already properly synchronized by the container, so I performed no additional locking here.  I didn’t find anything in the EJB specification to support or contradict this assumption.
  • The bean is now a @Singleton with bean-managed concurrency.  Even though it has bean-managed concurrency, there are no explicit synchronization primitives anywhere, because they are locked up (ha ha) inside the AbstractExecutorService innards, which do whatever they do, in disturbingly precise and awesome Doug Lea fashion.
  • The bean’s set of @Local business interfaces now includes AsynchronousExecutor.class, so that the container dispatch by way of SessionContext#getBusinessObject(Class) can work.  Like I said earlier, you could use this as a business interface, but it probably would be excessively narrow.
Thanks for all the comments and input.
Advertisements

Java-EE-compatible AbstractExecutorService Implementation

I had one of those should-have-seen-it-years-ago moments today.

I was reading through the EJB specification and was paying particular to one of my favorite sections, good ol’ section 21.2.2, which has a part in it that goes a little something like this:

An enterprise bean must not use thread synchronization primitives to synchronize execution of multiple instances, except if it is a Singleton session bean with bean-managed concurrency.

I have read this section probably, what, dozens of times, and have taken away from it that in general a session bean shouldn’t use the synchronized keyword, or various lock classes.  Then usually I move on.

Today I paused for a moment, and I’m glad I did.  What I realized—which is probably obvious to all of you—is that this does not say that a session bean cannot use the synchronized keyword.  It says that it cannot use the synchronized keyword to synchronize its own innards, because this might prevent the container from spreading calls out to bean instances across multiple hosts.

For probably years I’ve been studiously careful to avoid synchronization primitives or libraries that use them inside my various session beans, because I was just blindly following what I thought the specification said.  Turns out I was wrong.

So I turned around and immediately wrote this, which I’ve needed for eons:

@Local({Executor.class, ExecutorService.class})
@Stateless(name = “ExecutorService”)
public class ExecutorServiceBean extends AbstractExecutorService implements ExecutorService {

  @Resource
  private SessionContext sessionContext;

  @Override
  public void execute(final Runnable runnable) {
    if (runnable != null) {
      runnable.run();
    }
  }

  @Override
  public <T> Future<T> submit(final Callable<T> callable) {
    RunnableFuture<T> returnValue = null;
    if (this.sessionContext == null || !this.sessionContext.wasCancelCalled()) {
      returnValue = this.newTaskFor(callable);
      returnValue.run();
    }
    return returnValue;
  }

  @Override
  public boolean awaitTermination(final long timeout, final TimeUnit unit) {
    return false;
  }

  @Override
  public boolean isTerminated() {
    return false;
  }

  @Override
  public boolean isShutdown() {
    return false;
  }

  @Override
  public void shutdown() {

  }

  @Override
  public List<Runnable> shutdownNow() {
    return Collections.emptyList();
  }

}

It’s an AbstractExecutorService that is implemented as a stateless session bean itself via the @Asynchronous annotation.  The use of synchronized is confined to the AbstractExecutorService‘s underlying CompletionService, which is based around a LinkedBlockingQueue.  You can’t shut it down or terminate it, obviously, and less obviously you can’t portably keep track of the tasks in flight (although I’m thinking that either an @ApplicationScoped list of such tasks or a @SessionScoped list of such tasks could be @Injected here to do so) but short of that it should honor the contract.  Throw tomatoes.