Discussions

EJB design: Threads Recycled by J2EE Server

  1. Threads Recycled by J2EE Server (12 messages)

    I am using couple of Stateless Session Beans which are called by Business Delegate
    using EJBHomeFactory method.


    I have done the following in my EJB design.

    1. Since I am using Stateless SB, I am caching the EJBHome.
    2. Implementing Business Delegate as Singleton.
    3. Implementing EJBHomeFactory as Singleton.
    4. Not calling remove() on EJB as it is handled by Container.


    I am not sure where I am going wrong. But I noticed that every call to the EJB
        (BusinessDelegate --> EJBHomeFactory ---> SessionFacade)
     spawns a new thread on server. Is this normal? Eventually I come to a state
     where the server runs out of memory and cannot create any new native thread.
      
    Why are the threads not recycled???
     
    Can someone please advise where the problem lies...

    Thanks.

    Peter

    Threaded Messages (12)

  2. 1. Actually, for Stateless Session Bean also you need to invoke remove() method. The reason is, The remove() method won't remove the bean instance from pool, but it will help the container to clean up EJBObject created by the container to connect the client. So if you are done with the bean, as a safer side, just invoke the remove() method.

    2. Check your Factory code to make sure that, you use proper caching

    Hope this helps,
    Senthil.
  3. Thanks for the quick response Senthil.

    I tried what you had suggested.But the threads keep on increasing even if I call the same EJB.

    I am pasting some of the relevant code below. Please let me know if I am going wrong somewhere.

    Thanks.

    Peter.


    *********************************************************************
    client.java
    *********************************************************************
    // thin client app
    {
        StartupDelegate delegate = StartupDelegate.getInstance();
        System.out.println("DB Name : " + delegate.getDatabaseName());
        delegate = null;
        
     }
        
        
    *********************************************************************
    StartupDelegate.java
    *********************************************************************

    public class StartupDelegate {

      private final String FACADE_NAME = "StartupFacade";
      private Class FACADE_CLASS = StartupFacadeHome.class;

      //Singleton pattern implementation for the Business Delegate
      public static StartupDelegate delegate = null;

      // cache the EJBHome for Stateless Bean
      private static StartupFacadeHome facadeHome;

      private StartupDelegate() throws HomeFactoryException {
        EJBHomeFactory ejbFactory = EJBHomeFactory.getFactory();
        facadeHome = (StartupFacadeHome) ejbFactory.lookUpHome(FACADE_CLASS,
            FACADE_NAME);
      }

      /*
       * Get the singleton service object
       */
      public static synchronized StartupDelegate getInstance() throws
          HomeFactoryException {
        if (facadeHome == null) {
          delegate = new StartupDelegate();
        }
        return delegate;
      }

      /*
       * get the remote interface of the stateless session bean
       */
      private StartupFacadeRemote getStartupEJB() throws StartupException {
        StartupFacadeRemote facadeRemote = null;
        try {
          facadeRemote = (StartupFacadeRemote) facadeHome.create();
        } catch (Exception e) {
          throw new StartupException("Exception in getStartupEJB()", e);
        }
        return facadeRemote;
      }

      public String getDatabaseName() throws StartupException {
        String dbName = "";
        try {
          StartupFacadeRemote sfr = getStartupEJB();
          dbName = sfr.getDatabaseName();
          sfr.remove();
        } catch (Exception e) {
          throw new StartupException("Exception in getDatabaseName()", e);
        }
        return dbName;
      }
    }


    *********************************************************************
    EJBHomeFactory.java
    *********************************************************************
    public class EJBHomeFactory {

      private Map ejbHomes;
      private static EJBHomeFactory aFactorySingleton;
      private Context ctx;
      private static String theURL = "t3://localhost:7003";

      /**
       * EJBHomeFactory private constructor.
       */
      private EJBHomeFactory()
          throws NamingException {
        try {
          // get Initial Context
          Hashtable h = new Hashtable();
          h.put(Context.INITIAL_CONTEXT_FACTORY,
                "weblogic.jndi.WLInitialContextFactory");
          setAppURL();
          h.put(Context.PROVIDER_URL, theURL);
          ctx = new InitialContext(h);
          ejbHomes = Collections.synchronizedMap(new HashMap());
        } catch (Exception e) {
          e.printStackTrace();
        }
      }

      /*
       * Returns the singleton instance of the EJBHomeFactory
       */
      public static EJBHomeFactory getFactory()
          throws HomeFactoryException {
        try {
          if (EJBHomeFactory.aFactorySingleton == null) {
            EJBHomeFactory.aFactorySingleton = new EJBHomeFactory();
          }
        } catch (NamingException e) {
          throw new HomeFactoryException(e);
        }
        return EJBHomeFactory.aFactorySingleton;
      }

      /**
       * Lookup and cache an EJBHome object using a home class.
       */
      public EJBHome lookUpHome(Class homeClass)
          throws HomeFactoryException {

        EJBHome anEJBHome;
        anEJBHome = (EJBHome)this.ejbHomes.get(homeClass);
        try {
          if (anEJBHome == null) {
            anEJBHome = (EJBHome) PortableRemoteObject.narrow(ctx.lookup(
                homeClass.getName()), homeClass);
            this.ejbHomes.put(homeClass, anEJBHome);
          }
        } catch (ClassCastException e) {
          throw new HomeFactoryException(e);
        } catch (NamingException e) {
          throw new HomeFactoryException(e);
        }
        return anEJBHome;
      }

      /**
       * Lookup and cache an EJBHome object.
       */
      public EJBHome lookUpHome(Class homeClass, String jndiName)
          throws
          HomeFactoryException {

        EJBHome anEJBHome;

        anEJBHome = (EJBHome)this.ejbHomes.get(homeClass);
        try {
          if (anEJBHome == null) {
            System.out.println("finding HOME for first time");
            anEJBHome = (EJBHome) PortableRemoteObject.narrow(ctx.lookup(
                jndiName), homeClass);
            this.ejbHomes.put(homeClass, anEJBHome);
          }
        } catch (ClassCastException e) {
          throw new HomeFactoryException(e);
        } catch (NamingException e) {
          throw new HomeFactoryException(e);
        }
        return anEJBHome;
      }

      private void setAppURL() {
        AFOSystemInfo asi = new AFOSystemInfo();
        String serverName = asi.getAppServerName();
        String serverPort = asi.getAppServerPort();
        this.theURL = "t3://" + serverName + ":" + serverPort;
      }

    }

    *********** END of ALL CODE *************
  4. anEJBHome = (EJBHome)this.ejbHomes.get(homeClass);
        try {
          if (anEJBHome == null) {
            System.out.println("finding HOME for first time");
            anEJBHome = (EJBHome) PortableRemoteObject.narrow(ctx.lookup(
                jndiName), homeClass);
            this.ejbHomes.put(homeClass, anEJBHome);
    Peter, Is there any reason for doing this? like having the Key as StartupFacadeHome.class? I have a question, Can you change your client.java with some for loop and see if this statement displays all the times?
    System.out.println("finding HOME for first time");. I never tried storing the object with key as Class in Map.
    Senthil.
  5. Hi Senthil,

    I had referred to 'EJB Design Patterns' by Floyd Marinescu. This approach was mentioned there on page 230.


    Client.java
    -----------

        for (int i=0; i <= 100; i++) {
          StartupDelegate delegate = StartupDelegate.getInstance();
          System.out.println("DB Name : " + delegate.getDatabaseName());
          delegate = null;
        }


    It displayed "finding HOME for first time" just one.

    For some reasons, I feel the threads are not getting released and thereby recycled.

    Please let me know if you can think of anything more in this regard.

    Thanks for your help.

    Peter.

    p.s. what command did you use to give the white background with dotted border to the code in your reply.
  6. Threads Recycled by J2EE Server[ Go to top ]

    Hi,
    which j2ee server are you using??
    i tried simulating your code in websphere 5.1.1 and i am not facing any problems. May be your server configuration is causing a problem. just check max threads count in your server settings.

    --Mohit
  7. Threads Recycled by J2EE Server[ Go to top ]

    Hi Mohit,

    I am using Weblogic Server 7.0.4.

    I also tried to run my app on Windows XP and was monitoring the threads. What was strange was that the thread count was increasing for every call to the EJB. It was never going down. Was this the same on webshpere too or did you notice the thread count go down.

    Where can I get the information about max threads count.


    Thx.

    Peter
  8. Threads Recycled by J2EE Server[ Go to top ]

    Hi,

    In my case on websphere the thread count is maintained by the app server itself.
    when i open the trace log i found that the thread is spawned and killed after the container successfully complete the client request.
    I tried putting a for loop of max count 100000 in client.java and i am not facing any server out of memory error it executes like a cream.
    definitely the weblogic server settings is creating a problem in ur case.just see the configuration settings of weblogic server .
    I don't see any problem in your code because i excatly replicate the same thing .
    also try on other j2ee server and see what happens.

    -Mohit
  9. Threads Recycled by J2EE Server[ Go to top ]

    I found from the thread dump that lot of threads are created for log4j and not getting recycled.(see the thread dump below). I masked the log4j logging from my code. These log4j threads still get generated. Any ideas???


    Thread Dump

    "Thread-10" daemon prio=5 tid=0x113015d0 nid=0x838c waiting on monitor [0x133bf000..0x133bfdbc]
            at java.lang.Thread.sleep(Native Method)
            at org.apache.log4j.helpers.FileWatchdog.run(FileWatchdog.java:95)

    "Thread-9" daemon prio=5 tid=0x1195f1c0 nid=0x8390 waiting on monitor [0x1333f000..0x1333fdbc]
            at java.lang.Thread.sleep(Native Method)
            at org.apache.log4j.helpers.FileWatchdog.run(FileWatchdog.java:95)

    "Thread-8" daemon prio=5 tid=0x11b35e98 nid=0x8394 waiting on monitor [0x132bf000..0x132bfdbc]
            at java.lang.Thread.sleep(Native Method)
            at org.apache.log4j.helpers.FileWatchdog.run(FileWatchdog.java:95)
  10. issue Resolved finally[ Go to top ]

    I could resolve the issue finally. I am using DOMConfigurator.configureAndWatch() to dynamically read log4j property file. What I noticed is that this was spawning thread which was not getting recycled.

    By masking this line of code, I could get rid of all such threads thus not running into out of memory error.

    Thanks to Senthil & Mohit for all your help.
  11. Threads Recycled by J2EE Server[ Go to top ]

    Hi Peter,

    I'm experiencing this threading issue on one of the app servers.
    When i deploy a stateless session bean on Jboss and invokes a simple method on bean in a loop for 1000 times it works fine and there are no threading issues.
    But when i do on SUN ONE i can see that ones the max threshold of 999 threads on server is reached it stops responding and can only work until it is rebooted again.

    It will be good if you can actually post steps what you did to exactly to stop this behavior.

    And i think this can be the same issues what you have encounterd because ear files deployed on Jboss have log4j configuration where as when i deploy this ear files i have to add the log4j libraries beacuse sun one dosent ship that.
    So i'm inclined to think taht can be one of the isuues which you mentioned, but will invetsigate this weekend to see if this is the case, nevertheless if you can please post what steps you carried out that will be a good help.

    Vishal.
  12. Threads Recycled by J2EE Server[ Go to top ]

    Hi Vishal,

    I have not worked on JBoss. I am having Weblogic Server. But I am pretty much sure that JBoss might let you do similar stuff.

    1. After you have launched the server, run your application in a loop.
    2. At the point where the server says that it cannot create new native threads, get a thread dump. In weblogic I did it by running the command :

    java weblogic.Admin -url hostname:7001 -username admin -password mypassword THREAD_DUMP

    3. Take a look at all the threads that are waiting on monitor. Chances are that 90% of the threads will be spawned by same process. In my case, it was

    "Thread-14" daemon prio=5 tid=0x11999e90 nid=0x3388 waiting on monitor [0x135bf000..0x135bfdbc]
            at java.lang.Thread.sleep(Native Method)
            at org.apache.log4j.helpers.FileWatchdog.run(FileWatchdog.java:95)

    I knew that this has something to do with log4j framework that I was using for logging.

    4. So I started masking the logging lines, to see where this was being generated from. Eventually I found that the line
        DOMConfigurator.configureAndWatch(fileFileName, logFileWatchTime)
    was generating the threads that were not getting recycled. So I just went ahead and masked them.

    Now everything works fine. It is going to be a different day I will be spending trouble shooting why this is happening. I was using this, because I liked the idea that by doing so, you could dynamically change log4j properties file and not restart the server.

    But for now, I can leave with the idea of restarting the server if I change any configuration in log4j properties file. ;->

    What i would suggest is that instead of looping 1000 times, just loop 20 times. Get a thread dump before you run your client and after you run youyr client. See what threads are created new, and if most of them are for same process, you need to see where they care created. It might be a bug in your code or third party library that you are using.


    I hope this works for you.

    Peter.
  13. Threads Recycled by J2EE Server[ Go to top ]

    Hi Peter,

    Thanks for that, i'll try this weekend.
    Actually problem is with SUN ONE not with Jboss, it works fine.

    I 'll update this after how i go with this.
    Keep watching.

    Cheers...
    Vishal.