[EMAIL PROTECTED] wrote:
>
> On Fri, 15 Oct 1999, Peter Pilgrim wrote:
>
> > In fact code is wrong, at least in the conditionals statements.
> > Sorry about that
> >
> > public static NetworkPrinter getInstance()
> > {
> > // Point *A*
> > if ( thePrinter == null ) {
> > // Thread Safety - Double Guard technique
> > // Point *B*
> > synchronized( locker ) {
> > // Point *C*
> > // SHOULD BE A CRITICAL SECTION
> > if ( thePrinter == null ) {
> > thePrinter = new NetworkPrinter();
> > }
> > }
> > return (thePrinter);
> > }
> >
> > I can't understand what is the problem with the double guard technique.
> > You synchronize threads on the `locker' object and that should be
> > enough. In fact it should act like a `Mutex' (mutual exclusion).
>
> You are not synchronizing threads on the locker object. If you
> were doing that, you would have synchronization on the locker object
> for each thread that tried to use thePrinter. You don't. Nothing
> stops one thread from still being in the synchronized section while
> another thread uses a partially stored result.
>
> > If you have two threads t1 and t2 racing to create the singleton
> > which is not yet inited yet at Point A, both will get to Point B.
> > However only one of the two threads, assume by random choice t2,
> > will get to Point C, because of the use of the synchronized object
> > `locker'. Thread t2 will be allowed access to the critical section,
> > and t1 will be blocked until t2 leaves the critical section.
> > t2 will create the singleton and return it to its calling
> > thread. As it leaves the monitor `locker' it will unblock t1
> > from waiting, t1 will enter the critical section, and
> > discovers that the singleton `thePrinter' already exists.
> > It therefore returns the same singleton that t2 created.
> >
> > So converning invisiblity and visibility what's the problem?
>
> Your mistake is in assuming that just because the thePrinter reference is
> visible, everything that it references is visible, ie. the complete object
> is visible. That is _not_ necessarily the case because Java does _not_
> guarantee that all changes will be visible just because one is and because
> you have no synchronization on the thread that sees the thePrinter
> reference before entering the synchronized section.
>
> The thePrinter reference is not everything you need to be able to see, you
> have to be able to see the object itself as well.
>
> You need to read chapter 17 of the JLS very carefully:
>
> http://java.sun.com/docs/books/jls/html/17.doc.html#30206
>
> It summarizes things as:
>
> - Proper use of synchronization constructs will allow reliable
> transmission of values or sets of values from one thread to
> another through shared variables.
>
> - When a thread uses the value of a variable, the value it
> obtains is in fact a value stored into the variable by that
> thread or by some other thread. This is true even if the program
> does not contain code for proper synchronization. For example,
> if two threads store references to different objects into the
> same reference value, the variable will subsequently contain
> a reference to one object or the other, not a reference to some
> other object or a corrupted reference value. (There is a special
> exception for long and double values; see 17.4.)
>
> - In the absence of explicit synchronization, a Java implementation
> is free to update the main memory in an order that may be
> surprising. Therefore the programmer who prefers to avoid
> surprises should use explicit synchronization.
>
> "a Java implementation is free to update the main memory in an order that
> may be surprising."
>
> In another section where it describes the constraints for actions on
> a variable by a thread, it states:
>
> Provided that all the constraints above and below are obeyed, a
> load or store action may be issued at any time by any thread on
> any variable, at the whim of the implementation.
>
> Section 17.8 goes on:
>
> If a variable is not declared volatile, then the rules in the
> previous sections are relaxed slightly to allow store actions to
> occur earlier than would otherwise be permitted. The purpose of
> this relaxation is to allow optimizing Java compilers to perform
> certain kinds of code rearrangement that preserve the semantics of
> properly synchronized programs but might be caught in the act of
> performing memory actions out of order by programs that are not
> properly synchronized.
>
> See also section 17.11 for a sample program demonstrating the effects
> of out of order writes.
>
> (I'll be quiet now and won't be offtopic any more...)
I realized that the code example is completely flawed now
especially when I looked back at my real life singletons actually
in code. What you say about visibility and invisibility is
actually correct, especially if you use the work object
to synchronize with.
What I should have been locking is in fact the meta class
object itself. It should be `NetworkPrinter.class'.
Synchronizing on the class guarantees that there is no
conflict of interest between visibilty and invisibility.
// Throw away the `Object locker' becoz it is broken.
> > public static NetworkPrinter getInstance()
> > {
> > // Point *A*
> > if ( thePrinter == null ) {
> > // Thread Safety - Double Guard technique
> > // Point *B*
> > synchronized( locker ) {
synchronized( NetworkPrinter.class ) {
> > // Point *C*
> > // SHOULD BE A CRITICAL SECTION
> > if ( thePrinter == null ) {
> > thePrinter = new NetworkPrinter();
> > }
> > }
> > return (thePrinter);
> > }
--
Adios
Peter
-----------------------------------------------------------------
import std.Disclaimer; // More Java for your Lava, Mate.
"Give the man, what he wants. £££" [on Roy Keane, Quality Player]
----------------------------------------------------------------------
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]