AnsweredAssumed Answered

Slow multi-threaded execution due to oversynchronized blocks

Question asked by romanoff on Apr 13, 2011
Latest reply on Apr 20, 2011 by romanoff
Hi,

I have written a simple standalone test application (a JUnit test) that starts 5000 Runnable tasks on a j.u.c pool of 50 threads. Each task starts and executes the same simple BPMN process. H2 backend is used. There are no jobs or human tasks created during the execution of this process. Since processes are very simple and make no external invocations, they are supposed to be executed very fast. Main aim of this test is to see how fast Activiti can be if used without jobs, tasks and with disabled history, because I mostly need this mode of operation for my soft real-time use-case.

When I measured the performance of my application I noticed that it is rather slow for some reason. So, I decided to run it under a profiler. Profiler has discovered that a lot of time (>50%) is due to thread contention, because many of the worker threads are waiting for entering a critical section at a few places in the Activiti engine. It indicates that something is oversynchronized. Overall, the (ibatis-based) DB-backend seems to be the bottleneck.

Specifically, the ibatis runtime seems to be oversynchronized in the following two methods:
org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(String, String)
org.apache.ibatis.datasource.pooled.PooledDataSource.pushConnection(PooledConnection)

They synchronize on rather big blocks of code. And interestingly enough, the thread contention gets even worse when I increase the number of threads in my thread pool.

Another blocker is this method:
org.activiti.engine.impl.db.DbIdGenerator.getNextId()
Here we have:
  public synchronized long getNextId() {
    if (lastId<nextId) {
      getNewBlock();
    }
    return nextId++;
  }

I'm not an expert, but may be this synchronized block can be replaced by means of using AtomicLong or AtomicInteger?

Questions:
- Are these findings of a generic nature or is it only me, who sees this problem?
- Is there anything obviously wrong with my test, e.g. RuntimeService.startProcessInstanceByKey() is not supposed to be used from many concurrent threads at the same time?
- Is it possible to completely eliminate a need for a DB backend? I already switched the history off, but I still see quite some DB activity.

Best Regards,
  Leo

Outcomes