Re: Docs: EJB 3.1 Singleton documentation
On Tue, 2008-08-26 at 11:12 -0700, David Blevins wrote: On Aug 26, 2008, at 5:23 AM, Martin Vysny wrote: Many thanks for clarifying on how the locks works! One more question, just to be 100% sure :) . Recently I studied the java memory model a bit (there is beautiful FAQ located at [1]) and I'd like to ask: Let's assume that the execution exited some method m1 protected by Lock.READ (or Lock.WRITE) and is about to enter some method m2 (in the same Singleton bean) protected by Lock.WRITE. Is any operation invoked in method m1 guaranteed to happen-before any operation invoked in method m2? Those details are better described on this page: http://cwiki.apache.org/OPENEJBx30/singleton-beans.html I've slightly tweaked it to make the connection with ReadWriteLock stronger and to explicitly mention we use a ReentrantReadWriteLock. Hopefully people will follow those links. Here are a couple quotes from those docs that answer your questions a little more specifically: All ReadWriteLock implementations must guarantee that the memory synchronization effects of writeLock operations (as specified in the Lock interface) also hold with respect to the associated readLock. That is, a thread successfully acquiring the read lock will see all updates made upon previous release of the write lock. -- http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html Reentrancy also allows downgrading from the write lock to a read lock, by acquiring the write lock, then the read lock and then releasing the write lock. However, upgrading from a read lock to the write lock is not possible. -- http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html We could probably quote some of those two javadocs if there were one or two really critical things we think people should know above all else. If you have any thoughts on that regard that'd be great. -David Thanks David, the documentation now answers my question very clearly. I think you could explicitly quote this sentence: That is, a thread successfully acquiring the read lock will see all updates made upon previous release of the write lock. - it sums an answer to the question very nicely and simply. However, I have no other questions, the documentation is perfect, thanks :) Sincerely Martin signature.asc Description: This is a digitally signed message part
Re: Docs: EJB 3.1 Singleton documentation
On Mon, 2008-08-25 at 20:23 -0700, David Blevins wrote: Hi Martin, On Aug 25, 2008, at 4:33 AM, Martin Vysny wrote: Hi David, impressive work indeed, thank you very much! I am especially grateful for the Singleton and Startup functionality which I missed. Thanks! It's definitely great to have a standard way to do this in the EJB world. I have one question: in your example (the ComponentRegistryBean example) a simple HashMap is used which is thread unsafe. Does that mean that only a single thread (the one which created the bean) will access the bean? Nope, that's not it - multiple threads can access methods with Lock.READ. What does the specification say about the thread safety/multithreading issues? Must the bean be thread-safe or container will mark all methods as synchronized? Can the user code rely on some locking mechanisms (or invariants) performed by the container (for example, will Lock.WRITE always perform lock on the bean class?) Sorry if it is a dumb question and I'm missing something obvious :) Good feedback. Thank you for sending it! Clearly my explanation is not doing what it should :) I do see a bug too now that I look closer, too. The getComponents() method should return a copy of components.values() or someone could get a ConcurrentModificationException. I've changed/expanded on the text in the example. Pasted it here below as well. Let me know if it's any better. We'll keep trying till we get something that's easy to understand and doesn't leave the reader with a bunch of questions. Unless specified explicitly on the bean class or a method, the default @Lock value is @Lock(WRITE). The code above uses the @Lock(READ) annotation on bean class to change the default so that multi-threaded access is granted by default. We then only need to apply the @Lock(WRITE) annotation to the methods that modify the state of the bean. Essentially @Lock(READ) allows multithreaded access to the Singleton bean instance unless someone is invoking an @Lock(WRITE) method. With @Lock(WRITE), the thread invoking the bean will be guaranteed to have exclusive access to the Singleton bean instance for the duration of its invocation. This combination allows the bean instance to use data types that are not normally thread safe. Great care must still be used, though. In the example we see ComponentRegistryBean using a java.util.HashMap which is not synchronized. To make this ok we do three things: 1. Encapsulation. We don't expose the HashMap instance directly; including its iterators, key set, value set or entry set. 2. We use @Lock(WRITE) on the methods that mutate the map such as the put() and remove() methods. 3. We use @Lock(READ) on the get() and values() methods as they do not change the map state and are guaranteed not to be called at the same as any of the @Lock(WRITE) methods, so we know the state of the HashMap is no being mutated and therefore safe for reading. The end result is that the threading model for this bean will switch from multi-threaded access to single-threaded access dynamically as needed depending on the which methods are being invoked. This gives Singletons a bit of an advantage over Servlets for processing multi-threaded requests. http://cwiki.apache.org/OPENEJBx30/singleton-example.html Feel free to kick it back with changes/tweaks or other questions. Sometimes a word added here or there can make things more clear. These docs are likely going to be a primary source of singleton information for a while so we definitely want them to be as informative as possible. -David Many thanks for clarifying on how the locks works! One more question, just to be 100% sure :) . Recently I studied the java memory model a bit (there is beautiful FAQ located at [1]) and I'd like to ask: Let's assume that the execution exited some method m1 protected by Lock.READ (or Lock.WRITE) and is about to enter some method m2 (in the same Singleton bean) protected by Lock.WRITE. Is any operation invoked in method m1 guaranteed to happen-before any operation invoked in method m2? If not, then the example is still not thread-safe :) The happen-before is discussed in the What does synchronization do? section of the FAQ. Of course, if the EJB container simply uses correct synchronization then the answer is yes. However there may be other ways to synchronize (using DB locks or the like) which could not be as safe (in Java memory model). Please feel free to contact me if I wasn't clear enough. Martin [1]: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html signature.asc Description: This is a digitally signed message part
Re: Docs: EJB 3.1 Singleton documentation
On Aug 26, 2008, at 5:23 AM, Martin Vysny wrote: Many thanks for clarifying on how the locks works! One more question, just to be 100% sure :) . Recently I studied the java memory model a bit (there is beautiful FAQ located at [1]) and I'd like to ask: Let's assume that the execution exited some method m1 protected by Lock.READ (or Lock.WRITE) and is about to enter some method m2 (in the same Singleton bean) protected by Lock.WRITE. Is any operation invoked in method m1 guaranteed to happen-before any operation invoked in method m2? Those details are better described on this page: http://cwiki.apache.org/OPENEJBx30/singleton-beans.html I've slightly tweaked it to make the connection with ReadWriteLock stronger and to explicitly mention we use a ReentrantReadWriteLock. Hopefully people will follow those links. Here are a couple quotes from those docs that answer your questions a little more specifically: All ReadWriteLock implementations must guarantee that the memory synchronization effects of writeLock operations (as specified in the Lock interface) also hold with respect to the associated readLock. That is, a thread successfully acquiring the read lock will see all updates made upon previous release of the write lock. -- http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ReadWriteLock.html Reentrancy also allows downgrading from the write lock to a read lock, by acquiring the write lock, then the read lock and then releasing the write lock. However, upgrading from a read lock to the write lock is not possible. -- http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html We could probably quote some of those two javadocs if there were one or two really critical things we think people should know above all else. If you have any thoughts on that regard that'd be great. -David
Re: Docs: EJB 3.1 Singleton documentation
On Sat, 2008-08-23 at 02:04 -0700, David Blevins wrote: All, We've implemented the new EJB 3.1 javax.ejb.Singleton bean type. Singletons are a new type of Session bean being added to the EJB 3.1 specification. They provide some much needed functionality to the world of EJB and will be part of the coming OpenEJB 3.1 release. http://openejb.apache.org/singleton-beans.html http://openejb.apache.org/singleton-example.html Enjoy the first ever @Singleton bean implementation! A large part of our motivation for implementing this early is to gather feedback for the specification itself. This is one of those rare times where you can not only give feedback about our implementation but about the actual API as well! Give it a try and let us know what you think! -David Example source code: svn co http://svn.apache.org/repos/asf/openejb/trunk/openejb3/examples/simple-singleton/ Hi David, impressive work indeed, thank you very much! I am especially grateful for the Singleton and Startup functionality which I missed. I have one question: in your example (the ComponentRegistryBean example) a simple HashMap is used which is thread unsafe. Does that mean that only a single thread (the one which created the bean) will access the bean? Nope, that's not it - multiple threads can access methods with Lock.READ. What does the specification say about the thread safety/multithreading issues? Must the bean be thread-safe or container will mark all methods as synchronized? Can the user code rely on some locking mechanisms (or invariants) performed by the container (for example, will Lock.WRITE always perform lock on the bean class?) Sorry if it is a dumb question and I'm missing something obvious :) Sincerely, Martin signature.asc Description: This is a digitally signed message part
Re: Docs: EJB 3.1 Singleton documentation
Hi Martin, On Aug 25, 2008, at 4:33 AM, Martin Vysny wrote: Hi David, impressive work indeed, thank you very much! I am especially grateful for the Singleton and Startup functionality which I missed. Thanks! It's definitely great to have a standard way to do this in the EJB world. I have one question: in your example (the ComponentRegistryBean example) a simple HashMap is used which is thread unsafe. Does that mean that only a single thread (the one which created the bean) will access the bean? Nope, that's not it - multiple threads can access methods with Lock.READ. What does the specification say about the thread safety/multithreading issues? Must the bean be thread-safe or container will mark all methods as synchronized? Can the user code rely on some locking mechanisms (or invariants) performed by the container (for example, will Lock.WRITE always perform lock on the bean class?) Sorry if it is a dumb question and I'm missing something obvious :) Good feedback. Thank you for sending it! Clearly my explanation is not doing what it should :) I do see a bug too now that I look closer, too. The getComponents() method should return a copy of components.values() or someone could get a ConcurrentModificationException. I've changed/expanded on the text in the example. Pasted it here below as well. Let me know if it's any better. We'll keep trying till we get something that's easy to understand and doesn't leave the reader with a bunch of questions. Unless specified explicitly on the bean class or a method, the default @Lock value is @Lock(WRITE). The code above uses the @Lock(READ) annotation on bean class to change the default so that multi-threaded access is granted by default. We then only need to apply the @Lock(WRITE) annotation to the methods that modify the state of the bean. Essentially @Lock(READ) allows multithreaded access to the Singleton bean instance unless someone is invoking an @Lock(WRITE) method. With @Lock(WRITE), the thread invoking the bean will be guaranteed to have exclusive access to the Singleton bean instance for the duration of its invocation. This combination allows the bean instance to use data types that are not normally thread safe. Great care must still be used, though. In the example we see ComponentRegistryBean using a java.util.HashMap which is not synchronized. To make this ok we do three things: 1. Encapsulation. We don't expose the HashMap instance directly; including its iterators, key set, value set or entry set. 2. We use @Lock(WRITE) on the methods that mutate the map such as the put() and remove() methods. 3. We use @Lock(READ) on the get() and values() methods as they do not change the map state and are guaranteed not to be called at the same as any of the @Lock(WRITE) methods, so we know the state of the HashMap is no being mutated and therefore safe for reading. The end result is that the threading model for this bean will switch from multi-threaded access to single-threaded access dynamically as needed depending on the which methods are being invoked. This gives Singletons a bit of an advantage over Servlets for processing multi-threaded requests. http://cwiki.apache.org/OPENEJBx30/singleton-example.html Feel free to kick it back with changes/tweaks or other questions. Sometimes a word added here or there can make things more clear. These docs are likely going to be a primary source of singleton information for a while so we definitely want them to be as informative as possible. -David