Servlet concurrency/synchronization in Tomcat? - java

Is there a recommended way to synchronize Tomcat Servlet instances that happen to be competing for the same resource (like a file, or a database like MongoDB that isn't ACID)?
I'm familiar with thread synchronization to ensure two Java threads don't access the same Java object concurrently, but not with objects that have an existence outside the JRE.
edit: I only have 1 Tomcat server running. Whether that means different JVMs or not, I am not sure (I assume it's the same JVM, but potentially different threads).
edit: particular use case (but I'm asking the question in general):
Tomcat server acts as a file store, putting the raw files into a directory, and using MongoDB to store metadata. This is a pretty simple concept except for the concurrency issue. If there are two concurrent requests to store the same file, or to manage metadata on the same object at the same time, I need a way to resolve that and I'm not sure how. I suppose the easiest approach would be to serialize / queue requests somehow. Is there a way to implement queueing in Tomcat?

Typically, your various servlets will be running in the same JVM, and if they're not, you should be able to configure your servlet runner so this is the case. So you can arrange for them to see some central, shared resource manager.
Then for the actual gubbinry, if plain old synchronized isn't appropriate, look for example at the Semaphore class (link is to part of a tutorial/example I wrote a while ago in case it's helpful), which allows you to handle "pools" of resources.

If you are running one tomcat server and all your servlets are on one context you can always synchronize on a java object present on that context class loader. If you are running multiple contexts then the "synchronization object" can not reside in any particular context but needs to reside at a higher level that is shared by all the contexts. You can use the "common" class loader in tomcat 6.0 documentation here to place your "synchronization object" there which will then be shared among all contexts.

I have 2 cases, If you expect to access common resource for File editing within the same JVM you can use the "synchronized" in a Java function. If different JVMs and other none Java threads accessing the common resource you might try using manual file locking code giving each thread priority number in queue
For database i believe there's no concurrency issue.

Your external resource is going to be represented by Java object (e.g. java.io.File) in some way or another. You can always synchronize on that object if you need to.
Of course, that implies that said object would have to be shared across your servlet instances.

IMO you're asking for trouble. There are reasons why things like databases and shared file systems were invented. Trying to write your own using some Singleton class or semaphores is going to get ugly real quick. Find a storage solution that does this for you and save yourself a lot of headaches.

Related

How to cache objects on Tomcat across several WARs without putting the class-containing JAR into /lib/ext?

How can I cache server-wide (with cache scope spanning multiple WARs on this server) instances of classes from a JAR which is contained binary-identical in several WARs on a web container (server, e. g. Tomcat)?
<EDIT> I want to cache application data across WARs because the data is common to them. (It's a portal project, where it can be useful to share common data across different "views" implemented as different portlets deployed as different WARs, and using a Java object cache is much faster and more simple than using a central data-holding service.) </EDIT>
Is that possible at all? Or is it required to put such a JAR on a path accessed by a common parent classloader, like in /lib/ext ?
See: Java, Classpath, Classloading => Multiple Versions of the same jar/project
See: How does class loading work when the same class exists in different applications on the same server?
See: cast across classloader?
See: What is a serialVersionUID and why should I use it?
Yes, the best option is to put the classes in a class loader that is a parent of the two applications. If by lib/ext you mean JAVA_HOME/lib/ext, then I would not recommend that. Instead, you should put them in CATALINA_HOME/lib directory. See the Shared Library Files section of the documentation, which links to the Class Loader HOW-TO documentation.
You can add common classes (jars) to the shared.loader property in conf/catalina.properties. Those classes are available to all web apps but not tomcat itself.
If you implement a cache around a static singleton, then you would be able to access the objects from different web apps. I don't know if that is best practice however. For example it makes it hard to scale because it makes it impossible to load balance the apps onto many servers.
The answer seems to be "it depends".
If the JAR(s) (or classes) in question do not have dependencies conflicting with other components also deployed on the server, both proposed solutions (CATALINA_HOME/lib/ext/ and CATALINA_HOME/conf/catalina.properties :: shared.loader) should plainly work. Thus both are "correct answers" and I cannot see which one is "more correct" than the other.
However I missed a crucial detail when I first asked the question (but this does not invalidate it): In my case the JAR in question required Spring 4.2.9.RELEASE (and other dependencies), but other relevant WARs deployed on the same server contain and require Spring 3.0.7. (The objects to be cached do not depend on Spring, but the JAR was not designed with this problem in mind, and it also contains other related code depending on Spring which now would be very difficult to separate.)
Generally it should be possible to put into CATALINA_HOME/lib/ext/ what ever you want as long as all already deployed WARs contain everything they need: The "module first / parent last" class loading policy should prevent conflicts, even if (as in this example) Spring 4.2.9 is available to the parent classloader and Spring 3.0.7 is available to the WAR classloader. But it looks somewhat "unclean" and messy to me to mix-up things that way.
Therefore I decided to use the "to-be-cached" object's classloader hash code as the key in a map, in which the cached data are the values. Then all cached data is selected "by classloader" which automatically and transparently ensures assignment compatibility. If there is also another WAR deployed on the server which can change and thus invalidate the cached data, it can remove the whole map from the cache, forcing the "read-access" WARs to reload data on next access.
However this approach DOES NOT allow cross-WAR cacheing: Effectively every WAR will get its own private cache segment.
Another approach would be to deliberately transform all data to cache to/from e. g. JSON so as to get a "naturally global" data type like java.lang.String for the cached data. If chosen from the beginning of the project, to me this seems to be the cleanest way, but if there is already a complex (and generally working) implementation in place, this may cause some work to do.
Comments on this self-answer are welcome!

How to have a common object across multiple JVMs

There is an application that will need to have something like a look up table. This application can be started many times with different configurations. Is there a way to share a datastructure across JVMs. static would be valid within a JVM. Having a database would solve the issue. However, is there something simpler and fast?
You might use a file. Write the object to a file. There is no such thing as an object shared within JVMs because the life cycle of an Object is defined for and within a JVM.
File IO is usually faster than DB operations and simpler as well. But on the downside, ACID properties are not guaranteed by files and there could be inconsistencies if multiple processes try to read / write on the same file.

Sharing a java object across a cluster

My requirement is to share a java object across a cluster.
I get Confused
whether to write an EJB and share the java objects across the cluster
or
to use any third party such as infinispan or memecached or terracotta or
what about JCache?
with the constraint that
I can't change any of my source code with specific to any application
server (such as implementing the weblogic's singleton services).
I can't offer two builds for cluster and non cluster environment.
Performance should not be downgraded.
I am looking for only open source third party if I need to use it.
It need to work in weblogic , Websphere , Jbos and Tomcat too.
Can any one come up with the best option with these constraints in mind.
It can depend on the use case of the objects you want to share in the cluster.
I think it comes down to really the following options in most complex to least complex
Distributed cacheing
http://www.ehcache.org
Distributed cacheing is good if you need to ensure that an object is accessible from a cache on every node. I have used ehache to distribute quite successfully, no need to setup a terracotta server unless you need the scale, can just point instances together via rmi. Also works synchronously and asynchronously depending on requirements. Also cache replication is handy if nodes go down so cache is actually redundant and dont lose anything. Good if you need to make sure that the object has been updated across all the nodes.
Clustered Execution/data distribution
http://www.hazelcast.com/
Hazelcast is also a nice option as provides a way of executing java classes across a cluster. This is more useful if you have an object that represents a unit of work that needs to be performed and you dont care so much where it gets executed.
Also useful for distributed collections, i.e. a distributed map or queue
Roll your own RMI/Jgroups
Can write your own client/server but I think you will start to run into issues that the bigger frameworks solve if the requirements of the objects your dealing with starts to get complex. Realistically Hazelcast is really simple and should really eliminate the need to roll your own.
It's not open source, but Oracle Coherence would easily solve this problem.
If you need an implementation of JCache, the only one that I'm aware of being available today is Oracle Coherence; see: http://docs.oracle.com/middleware/1213/coherence/develop-applications/jcache_part.htm
For the sake of full disclosure, I work at Oracle. The opinions and views expressed in this post are my own, and do not necessarily reflect the opinions or views of my employer.
It is just an idea. you might want to check the exact implementation.
It will downgrade performance but I don't see how it is possible to avoid it.
It not an easy one to implement. might be you should consider load balance instead of clustering.
you might consider RMI and/or dynamic-proxy.
extract interface of your objects.
use RMI to access the real object (from all clusters even the one that actually holds the object)
in order to create RMI for an existing code you might use dynamic-proxy (again..not sure about implementation)
*dynamic proxy can wrap any object and do some pre and post task on each method invocation. in this case it might use the original object for RMI invocation
you will need connectivity between clusters in order to propogate the RMI object.

Singleton through several processes?

How can I write singleton to work through several processes? Is it possible?
For example I have code that works with Remote Service in Android. How can I write singleton for this purpose?
This thread is old, but the current accepted answer is wrong and misleading some people, so here we go.
Services in Android may run on the same process as your app, or a different process altogether.
If this is an Service defined by your own app for its internal use, it is probably running on the same process. Just don't set any of the process attributes on the Manifest. In that case, your service will run its tasks on either the main thread, or some background threads, and will share the same singleton instance with the rest of your app.
If this is a true remote Service running on a separate process, or a separate app, then what you are trying to achieve is much, much more difficult. Each process will have its own instance of the singleton, and they are in no way related to each other. This makes perfect sense, once you realise the different processes may not even be running the same version of the code.
If you really want to have a common object across processes (hint: you almost certainly don't), you'll need to create a shared memory space for its data, and implement some means of synchronisation. I'm sure there are full college lectures on that subject.
Remote Service you Create will always be singleton. You need to have an Interface to communicate between process using Android Interface Definition Language.
Android Interface Definition Language
See this Example
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html
public enum MySingleton {
SOLE;
//all class stuff
}
This one is singleton that is simply written, lazy and thread safe. You can use MySingleton.SOLE directly or put it to other variables, but they all will be only references to one only instance. You can use it in as many processes as you wish, it shall weather them all. (processes in Android are threads really)
It is not my idea, it is from Effective Java, Second Edition
As for global data using (put that requirement into the question, please), you could reach MySingleton.SOLE from everywhere. Static constants are global. Of course, names would be yours.
Of course any thing has its workaround. You can fool this singleton by classloading.
If you really want to have one instance for several different tasks, not threads, then the easy solution will be singleton build as Hybernate or other ORM object. All processes will see the same row in the same table with the same data. But I think it is the overkill for your task.

Share file storage index with multiple open applications in Java

I'm writing an HTTP Cache library for Java, and I'm trying to use that library in the same application which is started twice. I want to be able to share the cache between those instances.
What is the best solution for this? I also want to be able to write to that same storage, and it should be available for both instances.
Now I have a memory-based index of the files available to the cache, and this is not shareable over multiple VMs. It is serialized between startups, but this won't work for a shared cache.
According to the HTTP Spec, I can't just map files to URIs as there might be a variation of the same payload based on the request. I might, for instance, have a request that varies on the 'accept-language' header: In that case I would have a different file for each subsequent request which specifies a different language.
Any Ideas?
First, are you sure you want to write your own cache when there are several around? Things like:
ehcache
jboss cache
memcached
The first two are written in Java and the third can be accessed from Java. The first two also handle distributed caching, which is the general case of what you are asking for, I think. When they start up, they look to connect to other members so that they maintain a consistent cache across instances. Changes to one are reflected across instances. They can be set up to connect via multicast or with specific lists of servers specified.
Memcached typically works in a slightly different manner in that it is running externally to the Java processes you are running, so that all Java instances that start up will be talking to a common service. You can set up memcached to work in a distributed manner, but it does so by hashing keys so that the server you want to connect to can be determined by what it is you are looking for.
Doing a true distributed cache with consistent content is very hard to do well, which is why I suggest looking at an existing library. If you want to do it yourself, it would still help to look at those listed to see how they go about it and consider using something like JGroups as your underlying mechanism.
I think you should have a look at the WebDav-Specifications. It's an HTTP extension for sharing/editing/storing/versioning resources on a server. There exists an implementation as an Apache module, wich allows you a swift start using them.
So instead of implementing your own cache server implementation, you might be better off with a local Apache + mod-dav instance that is available to both of your applications.
Extra bonus: Since WebDav is a specified protocoll you get the interoperability with lots of tools for free.

Categories