5

I have a customer who's stuck in an EJB 3.0 environment. No @Singleton, no bean-managed concurrency :-(

Considering thread management and synchronization is forbidden by the ejb specification, how to implement a cache? In essence, I want an non-synchronized object cache for some costly operations.

ymajoros
  • 2,454
  • 3
  • 34
  • 60
  • Not sure i understand the segaste fully, but would applicationscoped cdi bean do? – Aksel Willgert Dec 27 '13 at 17:09
  • Nope, no CDI in this Java EE 5 environment & this wouldn't solve the synchronization problem. I don't need a singleton, just that @Singleton form ejb 3.1 + bean-managed concurrency would solve the problem. – ymajoros Dec 27 '13 at 20:43
  • have you considered to use a stateless with the pool size max value = 1? – Gabriel Aramburu Dec 28 '13 at 17:03
  • well, that's an interesting idea, but I don't want to have a pool size of 1 for all stateless beans ;-) – ymajoros Dec 28 '13 at 20:48
  • @ymajoros you can define this property for a particular bean, which server are you using? – Gabriel Aramburu Dec 29 '13 at 13:44
  • mostly glassfish, but this customer is using weblogic – ymajoros Dec 30 '13 at 08:49
  • anyway, I'm looking for a portable solution – ymajoros Dec 30 '13 at 08:49
  • I am not sure but I believe that since synchronization is an issue for you, I'd recommend HashMap. If synchronization needed, you may also look at ConcurrentHashMap. – Siva Tumma Jan 01 '14 at 12:00
  • I'm asking of an idea to avoid synchronization (thus also ConcurrentHashMap), while having to handle concurrent accesses, which HashMap won't cover. – ymajoros Jan 01 '14 at 12:25
  • Though you know better, but I am believing ConcurrentHashMap would be handy for you. [refering this](http://stackoverflow.com/questions/11793067/how-does-concurrenthashmap-work-internally). In any way, I believe you can definitely find something in `java.util.concurrent`. – Siva Tumma Jan 02 '14 at 13:13
  • The point is that the java ee spec forbids this. In a java ee 6 environment, this is allowed in certain conditions (bean managed concurrency), but my client is stuck to java ee 5. This is why I asked this question. – ymajoros Jan 02 '14 at 19:34

5 Answers5

1

The restriction of using static field and synchronization is stated in EJB 3.0 spec chapter 21.1.2. It also explains why.

• An enterprise bean must not use read/write static fields. Using read-only static fields is allowed. Therefore, it is recommended that all static fields in the enterprise bean class be declared as final.

This rule is required to ensure consistent runtime semantics because while some EJB containers may use a single JVM to execute all enterprise bean’s instances, others may distribute the instances across multiple JVMs.

• An enterprise bean must not use thread synchronization primitives to synchronize execution of multiple instances.

This is for the same reason as above. Synchronization would not work if the EJB container distributed enterprise bean’s instances across multiple JVMs.

If you implement a cache by singleton POJO, you may have the risk that actually there are multiple cache instances in each JVM if EJB container distributed EJB instances across multiple JVMs, for instance, in a cluster environment.

So it depends,

  • If the application isn't deployed in cluster environment, you could do that. As far as I know, WebLogic and GlassFish run one server instance in one JVM.
  • If data consistency is not restrictedly needed, you could also do that. Usually it's allowed when talking about "cache".

If it doesn't work for you, probably you should think about caching data outside of EJB container, e.g. put in Redis or Hazelcast.

aleung
  • 9,848
  • 3
  • 55
  • 69
  • Thanks for pointing out the why's, this is really interesting. I'd rather stick to the rule: don't handle synchronization yourself. You can't know for sure that containers will play nice with it, and you have no way to test perfectly, as it can only 'fail' (=dead lock) in rare circumstances. I think I'll just go for a unconsistent but non-synchronized cache. – ymajoros Jan 04 '14 at 08:23
0

I doubt whether I understood your question clearly or not! Following example is based on weblogic and eclipselink.

If you are using eclipselink JPA for your EJB, you can use cache for your every entities separately like this:

@Entity
@Cache(type=CacheType.SOFT)

If you want, you can enable caching for all the entities from the persistence.xml file also. This will be like this inside the property field(oracle doc's link):

<persistence-unit name="XYZ">
...
    <class>com.stack.Test</class>
    <properties>
        ...
        <property name="toplink.cache.type.default" value="Soft"/>
        ...
    </properties>
</persistence-unit>

Cache type can be different like Soft, Hard, Weak, Full, etc. Each of them is having their own meaning. You can find more about this cache type from here.

Sabuj Hassan
  • 38,281
  • 14
  • 75
  • 85
  • 1
    Your example isn't weblogic-specific (but will only work on eclipselink). But it's for JPA entities, and I'm looking for a generic cache. Eclipselink cache will also only cache entities with the primary key as key, which isn't sufficient in my case. I'm more looking for a generic solution to the threading problem. – ymajoros Dec 31 '13 at 22:34
0

Are even volatile variables forbidden in an EJB container? A volatile int variable provides some guarantees that are useful for multithreaded code. If a thread sees the change of a volatile variable, it is safe to assume that it sees everything that happened before.

Another idea would be a @Stateful bean that is instantiated only once (calls will be serialized by the container). I'm not sure about the implementation details, though.

marcus
  • 5,041
  • 3
  • 30
  • 36
  • By 'volatile variable', you mean a volatile field. Can't be used in a stateless bean. And you have atomicity problem. And it doesn't solve the problem at all: you still need a shared cache, my question was about its implementation. A stateful session bean isn't instanciated by you, and is state-related. So, you'll end up with multiple session beans (at least one per user session). Thanks for the suggestions, but they don't answer the question. – ymajoros Jan 04 '14 at 08:04
  • I wish to know how did you go about it. Let us know when you are done with some way. – Siva Tumma Jan 04 '14 at 09:25
  • So I ran out of ideas... Is this even possible? – marcus Jan 04 '14 at 15:17
  • I suggested my client to use ConcurrentSkipListMap, see my answer. – ymajoros Aug 27 '14 at 12:19
0

Well, I think that ConcurrentSkipListMap could be the solution: no synchronization but still thread-safe.

ymajoros
  • 2,454
  • 3
  • 34
  • 60
0

And I use Redis with Jedis for temporary values in memory.

See the link below

https://redislabs.com/lp/redis-java/

Redis comes with installers for multiple operating systems.

Example:

import redis.clients.jedis.Jedis; 

public class RedisStringJava { 
   public static void main(String[] args) { 
      //Connecting to Redis server on localhost 
      Jedis jedis = new Jedis("localhost"); 
      System.out.println("Connected"); 
      //set the data in redis string and expire in default time
      jedis.set("param_name", "Param value"); 
      // Get the stored data and print it 
      System.out.println("Stored string in redis:: "+ jedis.get("param_name")); 
   } 
}
Ronald Coarite
  • 4,460
  • 27
  • 31