Re: Guarantees around Servlet Filter initialization that sets an instance variable?

"Ludwig, Mark via Concurrency-interest" <[email protected]> Tue, 28 Apr 2020 11:58:20 +0000
Newsgroups gmane.comp.java.jsr.166-concurrency
Message-ID <BC5672F8AD4C054BAF167C9801500D1A01790391EB@USSLMMBX004.net.plm.eds.com>
Thank you.  My most-paranoid architect doesn't consider that language a
sufficient guarantee, so we’re going with another pattern I started using about
15 years ago, after I got my head around the final field semantics in Java
[1.]5, for lock-free "steady state" access elsewhere in our product.

I am interested in a little review of this pattern by JLS & JMM experts here.

Below is an example showing the design, in the context of the Filter interface.
Is there a name for this sort of design that uses a race that leads to the
exact, same data through different classes' methods – one synchronized and the
other unsynchronized?  The code below compiles.

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* Show steady-state lock-free access to data in doFilter
*/

class ShowDataAccess implements Filter
{
   private DataAccessor data = new SynchronizedDataAccessor();

   public void init(final FilterConfig config) throws ServletException
   {
      data.setAll(config);
   }

   public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)
         throws IOException, ServletException
   {
      System.out.println("doFilter config: " + data.getConfig());
   }

   public void destroy()
   {
      data = new SynchronizedDataAccessor();
   }

   private interface DataAccessor
   {
      public void setAll (FilterConfig config);
      public FilterConfig getConfig();
   }

   private class UnsynchronizedDataAccessor implements DataAccessor
   {
      private final FilterConfig config;
      public UnsynchronizedDataAccessor(FilterConfig config)
      {
         this.config = config;
      }
      public void setAll(FilterConfig config)
      {
         throw new UnsupportedOperationException("Logic error");
      }
      public FilterConfig getConfig()
      {
         return config;
      }
   }

   private class SynchronizedDataAccessor implements DataAccessor
   {
      public synchronized void setAll(FilterConfig config)
      {
         data = new UnsynchronizedDataAccessor(config); // Replace reference in parent that led here
      }
      public synchronized FilterConfig getConfig()
      {
         return data.getConfig();
      }
   }
}

Thanks,
Mark

From: Tim Peierls <[email protected]>
Sent: Wednesday, April 15, 2020 4:13 PM
To: Ludwig, Mark (DI SW LCS APPS CG&C) <[email protected]>
Cc: [email protected]
Subject: Re: [concurrency-interest] Guarantees around Servlet Filter initialization that sets an instance variable?


I’d be inclined to trust this line in the Javadoc<https://github.com/javaee/servlet-spec/blob/d3d0f3ba4dc9256122f01ebdd4be4fae2a586df3/src/main/java/javax/servlet/Filter.java#L58-L60>:

The init method must complete successfully before the filter is asked to do any filtering work.

"Complete successfully before" falls short of specifying that there is a happens-before edge between the actions in init() and those in doFilter(), but it’s hard to imagine an implementation for which that wouldn't be the case.

—tim


On Wed, Apr 15, 2020 at 4:46 PM Ludwig, Mark via Concurrency-interest <[email protected]<mailto:[email protected]>> wrote:
Greetings,

I hope this is a suitable topic for this list.

We are wondering if we need to arrange for some explicit synchronization in a Servlet Filter’s doFilter() method to safely refer to an instance variable that was set in the init() method.

We can’t find any mention of this, and without forcing memory fences, are concerned that we’re asking for trouble downstream somewhere.

(I think this works, consistently, in practice, “by accident,” because there is enough synchronization required between when the container instantiates the filter and calls init() in one thread and when the first doFilter() call comes along in a worker thread.  It seems to me that just having a worker thread pick up a request from a shared queue involves synchronization that “covers” this need in that thread.)

Thanks,

Mark Ludwig

Siemens Digital Industries Software
Lifecycle Collaboration
5939 Rice Creek Parkway
Shoreview, MN  55126 United States
Tel.      :+1 (651) 855-6140
Fax      :+1 (651) 855-6280
[email protected] <mailto:[email protected]>

_______________________________________________
Concurrency-interest mailing list
[email protected]<mailto:[email protected]>
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[email protected]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest