You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hivemind.apache.org by Howard Lewis Ship <hl...@gmail.com> on 2006/06/08 20:06:12 UTC

Double proxies vs. synchronization

The discussion at:
http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiate_05.html

has pointed out that, quite possibly, HiveMind has synchronization problems
w.r.t. instantiating services.

I'm not completely buying it. Looking at the code paths, it seems unlikely
to me that the compiler would have much opportunity to inline things.

Insidethe inner proxy (generated by SingletonServiceModel) we see the
following code:

private final synchronized MyServiceInterface _service()
{
  if (_service == null)
  {
    _service = (MyServiceInterface )
_serviceModel.getActualServiceImplementation();  // 1

_deferredProxy._setInner(_service);
// 2
  }

  return _service;
}

The memory model for Java is a tricky thing in concurrent code.

The first line of code (// 1) may not completely execute before (// 2) does.
That leaves a tiny window where _service is not fully instantiated and yet
is exposed (via the OuterProxy, aka _deferredProxy) to some other thread.
Further, the nature of these two statements means that //2 can't happen
before //1, just in parallel.  It's a pretty damn tight window.

Personally, I don't see it.  If (// 1) was just creating a new instance,
there might be something. However, getActualServiceImplementation() does a
lot of work, much of it delegated to other objects. The secondary objects
(service and interceptor factories) are hidden behind interfaces, interfaces
with multiple implementations (and therefore, not likely to be inlined by
the magic of Hotspot). The window shrinks from merely remotely possible to
zero.

Further, the scenarios necessary for even the remotely possible window are
not completely likely. If multiple threads all hit _service() at the same
time, they will be serialized by the synchronized lock on the method. What's
necessary is that, while //1 and //2 are both running, yet another thread
arrives inside the OuterProxy and sees the full service implementation (via
//2) before the initialization code (// 1) finished executing.

I'd love for every bit of code I write to be provably correct under any
circumstances.  For this to be an actual concern, we'd need the intersection
of many different unlikely scenarios to line up:  the threads arriving
inside the OuterProxy and InnerProxy at just the right times (highly
unlikely) along with Hotspot reording the code (distributed across at least
a dozen different classes) so that //2 occurs before //1 completes.
LIkelyhood falls close enough to zero to not be an issue.

I really like the fact that, once the service implementation is fully
instantiated, the inner proxy goes away, and the outer proxy can delegate to
the service implementation without needing any synchronization.

-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator and PMC Chair, Apache Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

Re: Double proxies vs. synchronization

Posted by Massimo Lusetti <ml...@gmail.com>.
On 6/9/06, Johan Lindquist <jo...@kawoo.co.uk> wrote:

> Just as a small side-note - we have been doing quite a bit of
> multi-threaded performance testing of our application and we didn't
> experience any problems so far.  And we had some pretty big hardware and
> a lot of clients.

Here too. In our typical environment we got Mule's nodes working on
the same LDAP in a multi-threaded way, so far the only problems were
given by the JDK implementation of the LDAP protocol.
Obviously Mule's container is HiveMind.

-- 
Massimo
http://meridio.blogspot.com

---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-dev-help@jakarta.apache.org


Re: Double proxies vs. synchronization

Posted by Johan Lindquist <jo...@kawoo.co.uk>.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi all,

Just as a small side-note - we have been doing quite a bit of
multi-threaded performance testing of our application and we didn't
experience any problems so far.  And we had some pretty big hardware and
a lot of clients.

Cheers,

Johan

James Carman wrote:
> Okay, I'm sold.  Leave it alone and wait until someone files a Jira issue
> with a stack trace! :-)
> 
> 
> -----Original Message-----
> From: Achim Hügen [mailto:achim.huegen@gmx.de] 
> Sent: Thursday, June 08, 2006 6:16 PM
> To: hivemind-dev@jakarta.apache.org
> Subject: Re: Double proxies vs. synchronization
> 
> This reminds me very much of the discussion about the
> 'double checked locking' pattern. Although there was the
> claim that it is broken it was a highly theoretical discussion.
> As far as I know no one ever proofed that claim on a modern
> jvm (> 1.1).
> For example a simple question has never been answered: What kind of
> exception occurs if an "not fully instantiated" class is called?
> 
> I severly doubt that any test scenario will proof the
> synchronization problem. And if any user will ever have this
> problem there is an easy work around: eager load the service
> and call some method on it.
> 
> Achim
> 
> Am Thu, 08 Jun 2006 20:06:12 +0200 schrieb Howard Lewis Ship  
> <hl...@gmail.com>:
> 
>> The discussion at:
>>
> http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiat
> e_05.html
>> has pointed out that, quite possibly, HiveMind has synchronization  
>> problems
>> w.r.t. instantiating services.
>>
>> I'm not completely buying it. Looking at the code paths, it seems  
>> unlikely
>> to me that the compiler would have much opportunity to inline things.
>>
>> Insidethe inner proxy (generated by SingletonServiceModel) we see the
>> following code:
>>
>> private final synchronized MyServiceInterface _service()
>> {
>>   if (_service == null)
>>   {
>>     _service = (MyServiceInterface )
>> _serviceModel.getActualServiceImplementation();  // 1
>>
>> _deferredProxy._setInner(_service);
>> // 2
>>   }
>>
>>   return _service;
>> }
>>
>> The memory model for Java is a tricky thing in concurrent code.
>>
>> The first line of code (// 1) may not completely execute before (// 2)  
>> does.
>> That leaves a tiny window where _service is not fully instantiated and  
>> yet
>> is exposed (via the OuterProxy, aka _deferredProxy) to some other thread.
>> Further, the nature of these two statements means that //2 can't happen
>> before //1, just in parallel.  It's a pretty damn tight window.
>>
>> Personally, I don't see it.  If (// 1) was just creating a new instance,
>> there might be something. However, getActualServiceImplementation() does  
>> a
>> lot of work, much of it delegated to other objects. The secondary objects
>> (service and interceptor factories) are hidden behind interfaces,  
>> interfaces
>> with multiple implementations (and therefore, not likely to be inlined by
>> the magic of Hotspot). The window shrinks from merely remotely possible  
>> to
>> zero.
>>
>> Further, the scenarios necessary for even the remotely possible window  
>> are
>> not completely likely. If multiple threads all hit _service() at the same
>> time, they will be serialized by the synchronized lock on the method.  
>> What's
>> necessary is that, while //1 and //2 are both running, yet another thread
>> arrives inside the OuterProxy and sees the full service implementation  
>> (via
>> //2) before the initialization code (// 1) finished executing.
>>
>> I'd love for every bit of code I write to be provably correct under any
>> circumstances.  For this to be an actual concern, we'd need the  
>> intersection
>> of many different unlikely scenarios to line up:  the threads arriving
>> inside the OuterProxy and InnerProxy at just the right times (highly
>> unlikely) along with Hotspot reording the code (distributed across at  
>> least
>> a dozen different classes) so that //2 occurs before //1 completes.
>> LIkelyhood falls close enough to zero to not be an issue.
>>
>> I really like the fact that, once the service implementation is fully
>> instantiated, the inner proxy goes away, and the outer proxy can  
>> delegate to
>> the service implementation without needing any synchronization.
>>
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: hivemind-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: hivemind-dev-help@jakarta.apache.org
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: hivemind-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: hivemind-dev-help@jakarta.apache.org
> 
> 
> 

- --
you too?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFEiTLN1Tv8wj7aQ34RAv4GAJwOIjnA/YM1nrmTTR030vQHUBo5bACgiEOF
OCLC/9q7NjlMZpjnHDRKUIs=
=f2+V
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-dev-help@jakarta.apache.org


RE: Double proxies vs. synchronization

Posted by James Carman <ja...@carmanconsulting.com>.
Okay, I'm sold.  Leave it alone and wait until someone files a Jira issue
with a stack trace! :-)


-----Original Message-----
From: Achim Hügen [mailto:achim.huegen@gmx.de] 
Sent: Thursday, June 08, 2006 6:16 PM
To: hivemind-dev@jakarta.apache.org
Subject: Re: Double proxies vs. synchronization

This reminds me very much of the discussion about the
'double checked locking' pattern. Although there was the
claim that it is broken it was a highly theoretical discussion.
As far as I know no one ever proofed that claim on a modern
jvm (> 1.1).
For example a simple question has never been answered: What kind of
exception occurs if an "not fully instantiated" class is called?

I severly doubt that any test scenario will proof the
synchronization problem. And if any user will ever have this
problem there is an easy work around: eager load the service
and call some method on it.

Achim

Am Thu, 08 Jun 2006 20:06:12 +0200 schrieb Howard Lewis Ship  
<hl...@gmail.com>:

> The discussion at:
>
http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiat
e_05.html
>
> has pointed out that, quite possibly, HiveMind has synchronization  
> problems
> w.r.t. instantiating services.
>
> I'm not completely buying it. Looking at the code paths, it seems  
> unlikely
> to me that the compiler would have much opportunity to inline things.
>
> Insidethe inner proxy (generated by SingletonServiceModel) we see the
> following code:
>
> private final synchronized MyServiceInterface _service()
> {
>   if (_service == null)
>   {
>     _service = (MyServiceInterface )
> _serviceModel.getActualServiceImplementation();  // 1
>
> _deferredProxy._setInner(_service);
> // 2
>   }
>
>   return _service;
> }
>
> The memory model for Java is a tricky thing in concurrent code.
>
> The first line of code (// 1) may not completely execute before (// 2)  
> does.
> That leaves a tiny window where _service is not fully instantiated and  
> yet
> is exposed (via the OuterProxy, aka _deferredProxy) to some other thread.
> Further, the nature of these two statements means that //2 can't happen
> before //1, just in parallel.  It's a pretty damn tight window.
>
> Personally, I don't see it.  If (// 1) was just creating a new instance,
> there might be something. However, getActualServiceImplementation() does  
> a
> lot of work, much of it delegated to other objects. The secondary objects
> (service and interceptor factories) are hidden behind interfaces,  
> interfaces
> with multiple implementations (and therefore, not likely to be inlined by
> the magic of Hotspot). The window shrinks from merely remotely possible  
> to
> zero.
>
> Further, the scenarios necessary for even the remotely possible window  
> are
> not completely likely. If multiple threads all hit _service() at the same
> time, they will be serialized by the synchronized lock on the method.  
> What's
> necessary is that, while //1 and //2 are both running, yet another thread
> arrives inside the OuterProxy and sees the full service implementation  
> (via
> //2) before the initialization code (// 1) finished executing.
>
> I'd love for every bit of code I write to be provably correct under any
> circumstances.  For this to be an actual concern, we'd need the  
> intersection
> of many different unlikely scenarios to line up:  the threads arriving
> inside the OuterProxy and InnerProxy at just the right times (highly
> unlikely) along with Hotspot reording the code (distributed across at  
> least
> a dozen different classes) so that //2 occurs before //1 completes.
> LIkelyhood falls close enough to zero to not be an issue.
>
> I really like the fact that, once the service implementation is fully
> instantiated, the inner proxy goes away, and the outer proxy can  
> delegate to
> the service implementation without needing any synchronization.
>



---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-dev-help@jakarta.apache.org



---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-dev-help@jakarta.apache.org


Re: Double proxies vs. synchronization

Posted by Achim Hügen <ac...@gmx.de>.
This reminds me very much of the discussion about the
'double checked locking' pattern. Although there was the
claim that it is broken it was a highly theoretical discussion.
As far as I know no one ever proofed that claim on a modern
jvm (> 1.1).
For example a simple question has never been answered: What kind of
exception occurs if an "not fully instantiated" class is called?

I severly doubt that any test scenario will proof the
synchronization problem. And if any user will ever have this
problem there is an easy work around: eager load the service
and call some method on it.

Achim

Am Thu, 08 Jun 2006 20:06:12 +0200 schrieb Howard Lewis Ship  
<hl...@gmail.com>:

> The discussion at:
> http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiate_05.html
>
> has pointed out that, quite possibly, HiveMind has synchronization  
> problems
> w.r.t. instantiating services.
>
> I'm not completely buying it. Looking at the code paths, it seems  
> unlikely
> to me that the compiler would have much opportunity to inline things.
>
> Insidethe inner proxy (generated by SingletonServiceModel) we see the
> following code:
>
> private final synchronized MyServiceInterface _service()
> {
>   if (_service == null)
>   {
>     _service = (MyServiceInterface )
> _serviceModel.getActualServiceImplementation();  // 1
>
> _deferredProxy._setInner(_service);
> // 2
>   }
>
>   return _service;
> }
>
> The memory model for Java is a tricky thing in concurrent code.
>
> The first line of code (// 1) may not completely execute before (// 2)  
> does.
> That leaves a tiny window where _service is not fully instantiated and  
> yet
> is exposed (via the OuterProxy, aka _deferredProxy) to some other thread.
> Further, the nature of these two statements means that //2 can't happen
> before //1, just in parallel.  It's a pretty damn tight window.
>
> Personally, I don't see it.  If (// 1) was just creating a new instance,
> there might be something. However, getActualServiceImplementation() does  
> a
> lot of work, much of it delegated to other objects. The secondary objects
> (service and interceptor factories) are hidden behind interfaces,  
> interfaces
> with multiple implementations (and therefore, not likely to be inlined by
> the magic of Hotspot). The window shrinks from merely remotely possible  
> to
> zero.
>
> Further, the scenarios necessary for even the remotely possible window  
> are
> not completely likely. If multiple threads all hit _service() at the same
> time, they will be serialized by the synchronized lock on the method.  
> What's
> necessary is that, while //1 and //2 are both running, yet another thread
> arrives inside the OuterProxy and sees the full service implementation  
> (via
> //2) before the initialization code (// 1) finished executing.
>
> I'd love for every bit of code I write to be provably correct under any
> circumstances.  For this to be an actual concern, we'd need the  
> intersection
> of many different unlikely scenarios to line up:  the threads arriving
> inside the OuterProxy and InnerProxy at just the right times (highly
> unlikely) along with Hotspot reording the code (distributed across at  
> least
> a dozen different classes) so that //2 occurs before //1 completes.
> LIkelyhood falls close enough to zero to not be an issue.
>
> I really like the fact that, once the service implementation is fully
> instantiated, the inner proxy goes away, and the outer proxy can  
> delegate to
> the service implementation without needing any synchronization.
>



---------------------------------------------------------------------
To unsubscribe, e-mail: hivemind-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: hivemind-dev-help@jakarta.apache.org


Re: Double proxies vs. synchronization

Posted by Howard Lewis Ship <hl...@gmail.com>.
The best approach would be to merge OuterProxy and InnerProxy into just a
Proxy. But that means that on every service method invocation, you go
through a (short) synchronized block.  I consider that "sand in the works"
that could lead to an aggregate slowdown. Perhaps a micro-benchmark would
yield orders-of-magnitude comparison.

Under JDK 1.5, a read/write lock might be better. However, I suspect that
the overhead of a read/write lock is higher than synchronized, even though
it allows true concurrency.

I can't reiterate enough ... I don't think anyone ever will see this in the
real world.  And if they do, use eager loading on the service in question,
so that it is fully instantiated during Registry startup.

On 6/8/06, James Carman <ja...@carmanconsulting.com> wrote:
>
>  Well, what's the performance hit to make this "correct" in the eyes of
> the academics?  Maybe we can do some benchmarking.
>
>
>
>
>  ------------------------------
>
> *From:* Howard Lewis Ship [mailto:hlship@gmail.com]
> *Sent:* Thursday, June 08, 2006 2:29 PM
>
> *To:* hivemind-dev@jakarta.apache.org
> *Subject:* Re: Double proxies vs. synchronization
>
>
>
> In my analysis, the likelyhood of this every occuring, correct or not, is
> extremely remote.
>
> On 6/8/06, *James Carman* < james@carmanconsulting.com> wrote:
>
> We should really make sure this stuff is correct.  These are the most
> annoying types of bugs to track down.  Maybe we can make the synchronization
> strategy pluggable?
>
>
>   ------------------------------
>
> *From:* Howard Lewis Ship [mailto:hlship@gmail.com]
> *Sent:* Thursday, June 08, 2006 2:06 PM
> *To:* hivemind-dev@jakarta.apache.org
> *Subject:* Double proxies vs. synchronization
>
>
>
> The discussion at:
> http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiate_05.html
>
> has pointed out that, quite possibly, HiveMind has synchronization
> problems w.r.t. instantiating services.
>
> I'm not completely buying it. Looking at the code paths, it seems unlikely
> to me that the compiler would have much opportunity to inline things.
>
> Insidethe inner proxy (generated by SingletonServiceModel) we see the
> following code:
>
> private final synchronized MyServiceInterface _service()
> {
>   if (_service == null)
>   {
>     _service = (MyServiceInterface )
> _serviceModel.getActualServiceImplementation();  // 1
>
> _deferredProxy._setInner(_service);
> // 2
>   }
>
>   return _service;
> }
>
> The memory model for Java is a tricky thing in concurrent code.
>
> The first line of code (// 1) may not completely execute before (// 2)
> does. That leaves a tiny window where _service is not fully instantiated and
> yet is exposed (via the OuterProxy, aka _deferredProxy) to some other
> thread. Further, the nature of these two statements means that //2 can't
> happen before //1, just in parallel.  It's a pretty damn tight window.
>
> Personally, I don't see it.  If (// 1) was just creating a new instance,
> there might be something. However, getActualServiceImplementation() does a
> lot of work, much of it delegated to other objects. The secondary objects
> (service and interceptor factories) are hidden behind interfaces, interfaces
> with multiple implementations (and therefore, not likely to be inlined by
> the magic of Hotspot). The window shrinks from merely remotely possible to
> zero.
>
> Further, the scenarios necessary for even the remotely possible window are
> not completely likely. If multiple threads all hit _service() at the same
> time, they will be serialized by the synchronized lock on the method. What's
> necessary is that, while //1 and //2 are both running, yet another thread
> arrives inside the OuterProxy and sees the full service implementation (via
> //2) before the initialization code (// 1) finished executing.
>
> I'd love for every bit of code I write to be provably correct under any
> circumstances.  For this to be an actual concern, we'd need the intersection
> of many different unlikely scenarios to line up:  the threads arriving
> inside the OuterProxy and InnerProxy at just the right times (highly
> unlikely) along with Hotspot reording the code (distributed across at least
> a dozen different classes) so that //2 occurs before //1 completes.
> LIkelyhood falls close enough to zero to not be an issue.
>
> I really like the fact that, once the service implementation is fully
> instantiated, the inner proxy goes away, and the outer proxy can delegate to
> the service implementation without needing any synchronization.
>
> --
> Howard M. Lewis Ship
> Independent J2EE / Open-Source Java Consultant
> Creator and PMC Chair, Apache Tapestry
> Creator, Jakarta HiveMind
>
> Professional Tapestry training, mentoring, support
> and project work.   http://howardlewisship.com
>
>
>
>
> --
> Howard M. Lewis Ship
> Independent J2EE / Open-Source Java Consultant
> Creator and PMC Chair, Apache Tapestry
> Creator, Jakarta HiveMind
>
> Professional Tapestry training, mentoring, support
> and project work.  http://howardlewisship.com
>



-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator and PMC Chair, Apache Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

RE: Double proxies vs. synchronization

Posted by James Carman <ja...@carmanconsulting.com>.
Well, what's the performance hit to make this "correct" in the eyes of the
academics?  Maybe we can do some benchmarking.

 

 

  _____  

From: Howard Lewis Ship [mailto:hlship@gmail.com] 
Sent: Thursday, June 08, 2006 2:29 PM
To: hivemind-dev@jakarta.apache.org
Subject: Re: Double proxies vs. synchronization

 

In my analysis, the likelyhood of this every occuring, correct or not, is
extremely remote.

On 6/8/06, James Carman < james@carmanconsulting.com
<ma...@carmanconsulting.com> > wrote:

We should really make sure this stuff is correct.  These are the most
annoying types of bugs to track down.  Maybe we can make the synchronization
strategy pluggable? 

 

  _____  

From: Howard Lewis Ship [mailto:hlship@gmail.com] 
Sent: Thursday, June 08, 2006 2:06 PM
To: hivemind-dev@jakarta.apache.org
Subject: Double proxies vs. synchronization

 

The discussion at:
http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiat
e_05.html

has pointed out that, quite possibly, HiveMind has synchronization problems
w.r.t. instantiating services.

I'm not completely buying it. Looking at the code paths, it seems unlikely
to me that the compiler would have much opportunity to inline things.  

Insidethe inner proxy (generated by SingletonServiceModel) we see the
following code: 

private final synchronized MyServiceInterface _service()
{
  if (_service == null)
  {
    _service = (MyServiceInterface )
_serviceModel.getActualServiceImplementation();  // 1
    _deferredProxy._setInner(_service);
// 2 
  }

  return _service;
}

The memory model for Java is a tricky thing in concurrent code.

The first line of code (// 1) may not completely execute before (// 2) does.
That leaves a tiny window where _service is not fully instantiated and yet
is exposed (via the OuterProxy, aka _deferredProxy) to some other thread.
Further, the nature of these two statements means that //2 can't happen
before //1, just in parallel.  It's a pretty damn tight window. 

Personally, I don't see it.  If (// 1) was just creating a new instance,
there might be something. However, getActualServiceImplementation() does a
lot of work, much of it delegated to other objects. The secondary objects
(service and interceptor factories) are hidden behind interfaces, interfaces
with multiple implementations (and therefore, not likely to be inlined by
the magic of Hotspot). The window shrinks from merely remotely possible to
zero.  

Further, the scenarios necessary for even the remotely possible window are
not completely likely. If multiple threads all hit _service() at the same
time, they will be serialized by the synchronized lock on the method. What's
necessary is that, while //1 and //2 are both running, yet another thread
arrives inside the OuterProxy and sees the full service implementation (via
//2) before the initialization code (// 1) finished executing. 

I'd love for every bit of code I write to be provably correct under any
circumstances.  For this to be an actual concern, we'd need the intersection
of many different unlikely scenarios to line up:  the threads arriving
inside the OuterProxy and InnerProxy at just the right times (highly
unlikely) along with Hotspot reording the code (distributed across at least
a dozen different classes) so that //2 occurs before //1 completes.
LIkelyhood falls close enough to zero to not be an issue. 

I really like the fact that, once the service implementation is fully
instantiated, the inner proxy goes away, and the outer proxy can delegate to
the service implementation without needing any synchronization.

-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator and PMC Chair, Apache Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.   http://howardlewisship.com 




-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator and PMC Chair, Apache Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support 
and project work.  http://howardlewisship.com 


Re: Double proxies vs. synchronization

Posted by Howard Lewis Ship <hl...@gmail.com>.
In my analysis, the likelyhood of this every occuring, correct or not, is
extremely remote.

On 6/8/06, James Carman <ja...@carmanconsulting.com> wrote:
>
>  We should really make sure this stuff is correct.  These are the most
> annoying types of bugs to track down.  Maybe we can make the synchronization
> strategy pluggable?
>
>
>  ------------------------------
>
> *From:* Howard Lewis Ship [mailto:hlship@gmail.com]
> *Sent:* Thursday, June 08, 2006 2:06 PM
> *To:* hivemind-dev@jakarta.apache.org
> *Subject:* Double proxies vs. synchronization
>
>
>
> The discussion at:
> http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiate_05.html
>
> has pointed out that, quite possibly, HiveMind has synchronization
> problems w.r.t. instantiating services.
>
> I'm not completely buying it. Looking at the code paths, it seems unlikely
> to me that the compiler would have much opportunity to inline things.
>
> Insidethe inner proxy (generated by SingletonServiceModel) we see the
> following code:
>
> private final synchronized MyServiceInterface _service()
> {
>   if (_service == null)
>   {
>     _service = (MyServiceInterface )
> _serviceModel.getActualServiceImplementation();  // 1
>
> _deferredProxy._setInner(_service);
> // 2
>   }
>
>   return _service;
> }
>
> The memory model for Java is a tricky thing in concurrent code.
>
> The first line of code (// 1) may not completely execute before (// 2)
> does. That leaves a tiny window where _service is not fully instantiated and
> yet is exposed (via the OuterProxy, aka _deferredProxy) to some other
> thread. Further, the nature of these two statements means that //2 can't
> happen before //1, just in parallel.  It's a pretty damn tight window.
>
> Personally, I don't see it.  If (// 1) was just creating a new instance,
> there might be something. However, getActualServiceImplementation() does a
> lot of work, much of it delegated to other objects. The secondary objects
> (service and interceptor factories) are hidden behind interfaces, interfaces
> with multiple implementations (and therefore, not likely to be inlined by
> the magic of Hotspot). The window shrinks from merely remotely possible to
> zero.
>
> Further, the scenarios necessary for even the remotely possible window are
> not completely likely. If multiple threads all hit _service() at the same
> time, they will be serialized by the synchronized lock on the method. What's
> necessary is that, while //1 and //2 are both running, yet another thread
> arrives inside the OuterProxy and sees the full service implementation (via
> //2) before the initialization code (// 1) finished executing.
>
> I'd love for every bit of code I write to be provably correct under any
> circumstances.  For this to be an actual concern, we'd need the intersection
> of many different unlikely scenarios to line up:  the threads arriving
> inside the OuterProxy and InnerProxy at just the right times (highly
> unlikely) along with Hotspot reording the code (distributed across at least
> a dozen different classes) so that //2 occurs before //1 completes.
> LIkelyhood falls close enough to zero to not be an issue.
>
> I really like the fact that, once the service implementation is fully
> instantiated, the inner proxy goes away, and the outer proxy can delegate to
> the service implementation without needing any synchronization.
>
> --
> Howard M. Lewis Ship
> Independent J2EE / Open-Source Java Consultant
> Creator and PMC Chair, Apache Tapestry
> Creator, Jakarta HiveMind
>
> Professional Tapestry training, mentoring, support
> and project work.   http://howardlewisship.com
>



-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator and PMC Chair, Apache Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.  http://howardlewisship.com

RE: Double proxies vs. synchronization

Posted by James Carman <ja...@carmanconsulting.com>.
We should really make sure this stuff is correct.  These are the most
annoying types of bugs to track down.  Maybe we can make the synchronization
strategy pluggable? 

 

  _____  

From: Howard Lewis Ship [mailto:hlship@gmail.com] 
Sent: Thursday, June 08, 2006 2:06 PM
To: hivemind-dev@jakarta.apache.org
Subject: Double proxies vs. synchronization

 

The discussion at:
http://howardlewisship.com/blog/2006/06/whoa-spring-doesnt-lazily-instantiat
e_05.html

has pointed out that, quite possibly, HiveMind has synchronization problems
w.r.t. instantiating services.

I'm not completely buying it. Looking at the code paths, it seems unlikely
to me that the compiler would have much opportunity to inline things.  

Insidethe inner proxy (generated by SingletonServiceModel) we see the
following code: 

private final synchronized MyServiceInterface _service()
{
  if (_service == null)
  {
    _service = (MyServiceInterface )
_serviceModel.getActualServiceImplementation();  // 1
    _deferredProxy._setInner(_service);
// 2 
  }

  return _service;
}

The memory model for Java is a tricky thing in concurrent code.

The first line of code (// 1) may not completely execute before (// 2) does.
That leaves a tiny window where _service is not fully instantiated and yet
is exposed (via the OuterProxy, aka _deferredProxy) to some other thread.
Further, the nature of these two statements means that //2 can't happen
before //1, just in parallel.  It's a pretty damn tight window. 

Personally, I don't see it.  If (// 1) was just creating a new instance,
there might be something. However, getActualServiceImplementation() does a
lot of work, much of it delegated to other objects. The secondary objects
(service and interceptor factories) are hidden behind interfaces, interfaces
with multiple implementations (and therefore, not likely to be inlined by
the magic of Hotspot). The window shrinks from merely remotely possible to
zero.  

Further, the scenarios necessary for even the remotely possible window are
not completely likely. If multiple threads all hit _service() at the same
time, they will be serialized by the synchronized lock on the method. What's
necessary is that, while //1 and //2 are both running, yet another thread
arrives inside the OuterProxy and sees the full service implementation (via
//2) before the initialization code (// 1) finished executing. 

I'd love for every bit of code I write to be provably correct under any
circumstances.  For this to be an actual concern, we'd need the intersection
of many different unlikely scenarios to line up:  the threads arriving
inside the OuterProxy and InnerProxy at just the right times (highly
unlikely) along with Hotspot reording the code (distributed across at least
a dozen different classes) so that //2 occurs before //1 completes.
LIkelyhood falls close enough to zero to not be an issue. 

I really like the fact that, once the service implementation is fully
instantiated, the inner proxy goes away, and the outer proxy can delegate to
the service implementation without needing any synchronization.

-- 
Howard M. Lewis Ship
Independent J2EE / Open-Source Java Consultant
Creator and PMC Chair, Apache Tapestry
Creator, Jakarta HiveMind

Professional Tapestry training, mentoring, support
and project work.   http://howardlewisship.com