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.
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.
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.
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.
Well, I think that ConcurrentSkipListMap could be the solution: no synchronization but still thread-safe.