Tapestry
  1. Tapestry
  2. TAPESTRY-2141

NullPointerExceptions under JDK 1.5 due to underlying ThreadLocal bug

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 5.0.10
    • Fix Version/s: 5.0.11
    • Component/s: tapestry-ioc
    • Labels:
      None
    • Environment:
      jre 1.5

      Description

      There is a ThreadLocal bug that might be a source of problems for following code:

      here is a non trivial example that is broken,
      I'll try to make a trivial one that fails

      a simple page with test link
      <t:eventlink event="test">test</t:eventlink>

      page:
      @Inject private HibernateSessionManager _sessionManager;
      @Inject private ThreadCleanupHub _cleanupHub;

      public void onTest(){
      new Thread(new Runnable(){
      public void run()

      { User user = (User) _sessionManager.getSession().load(User.class, Long.valueOf(1L)); user.setName(user.getName()+"1"); _cleanupHub.cleanup(); }

      }).start();
      }

      for java 1.5 this code fails to save data (threadCleanupHub looses listener list )
      and it works fo 1.6

      here's a link to articles about this bug
      http://crazybob.org/2006/07/hard-core-java-threadlocal.html

      and the bug
      http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5025230

      it also makes this snippet not working
      http://wiki.apache.org/tapestry/Tapestry5HowToRunTaskInThread

        Issue Links

          Activity

          Hide
          Davor Hrg added a comment -

          the bug mentioned for happens if ThreadLocal.initialValue() happens inside another ThreadLocal.initialValue()

          this is exactly the case if any threaded service is initialized and when threadCleanupHub is not initialized yet.

          It is because PerThreadServiceCreator uses ThreadLocal and inside initValue() generates a new instance of a service by calling
          ObjectCreator.createObject() .. which actualy calls a build method.

          Build method for HibernateSesionManager adds a listener to ThreadCleanupHub
          ThreadCleanupHub then gets initialized and calls own initialValue() and things get messed up.

          I'm not yet grasping the problem to it's full depth, but possible workarrounds are comming in mind..

          maybe this was noticed and solved in T4 ...

          Show
          Davor Hrg added a comment - the bug mentioned for happens if ThreadLocal.initialValue() happens inside another ThreadLocal.initialValue() this is exactly the case if any threaded service is initialized and when threadCleanupHub is not initialized yet. It is because PerThreadServiceCreator uses ThreadLocal and inside initValue() generates a new instance of a service by calling ObjectCreator.createObject() .. which actualy calls a build method. Build method for HibernateSesionManager adds a listener to ThreadCleanupHub ThreadCleanupHub then gets initialized and calls own initialValue() and things get messed up. I'm not yet grasping the problem to it's full depth, but possible workarrounds are comming in mind.. maybe this was noticed and solved in T4 ...
          Hide
          Davor Hrg added a comment -

          one workarround is to initialize ThreadCleanupHub early by adding a dummy listener at the begining of a newly created thread,
          and other workarround is already happening for tapestry http requests.

          If first threaded service accessed is adding something to ThreadCleanupHub code will break,
          but for tapestry web requests first threaded service called is RequestGlobals which does not
          add anything to ThreadCleanupHub. This way ThreadCleanupHub is initialized and problematic
          service like HibernateSessionManager works ok.

          I suppose this is bug waiting to happen..
          if for some reason a "problematic" service initializes first.

          Show
          Davor Hrg added a comment - one workarround is to initialize ThreadCleanupHub early by adding a dummy listener at the begining of a newly created thread, and other workarround is already happening for tapestry http requests. If first threaded service accessed is adding something to ThreadCleanupHub code will break, but for tapestry web requests first threaded service called is RequestGlobals which does not add anything to ThreadCleanupHub. This way ThreadCleanupHub is initialized and problematic service like HibernateSessionManager works ok. I suppose this is bug waiting to happen.. if for some reason a "problematic" service initializes first.
          Hide
          Howard M. Lewis Ship added a comment -

          I've been thinking that we could coalesce all ThreadLocal's into a single map .... expand and rename ThreadCleanupHub to be ThreadData, adding methods for storing and retrieving thread-local data. Clients would need to provide their own keys (I think a key type of Object would work fine).

          Show
          Howard M. Lewis Ship added a comment - I've been thinking that we could coalesce all ThreadLocal's into a single map .... expand and rename ThreadCleanupHub to be ThreadData, adding methods for storing and retrieving thread-local data. Clients would need to provide their own keys (I think a key type of Object would work fine).
          Hide
          Howard M. Lewis Ship added a comment -

          This looks pretty fixed; I think the specific case was when a per-thread service was using a TheadLocal to create the per-thread instance AND asking the ThreadCleanupHub to register a listener, as that would also create a per-thread instance inside a ThreadLocal to store the list. Now there's only one ThreadLocal in that scenario.

          Show
          Howard M. Lewis Ship added a comment - This looks pretty fixed; I think the specific case was when a per-thread service was using a TheadLocal to create the per-thread instance AND asking the ThreadCleanupHub to register a listener, as that would also create a per-thread instance inside a ThreadLocal to store the list. Now there's only one ThreadLocal in that scenario.

            People

            • Assignee:
              Howard M. Lewis Ship
              Reporter:
              Davor Hrg
            • Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development