-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Struts/Hibernate/Runnable/Tomcat multithreading issue
PostPosted: Wed Jul 05, 2006 1:14 pm 
Regular
Regular

Joined: Tue Nov 23, 2004 7:42 am
Posts: 82
Location: London, England
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

Hibernate version:
2.1.6

Full stack trace of any exception that occurs:
None

I integrated the HibernateFilter from the Hibernate 2 version of Caveat Emptor into our application and came across a strange issue with multithreading (I have searched the forum for similar problems/fixes and not seen any)

I have a consumer (implements Runnable) that does database access/updating). This is managed by a singleton that is created when needed. Our web application is written using Struts and things to process may be added to the consumer through the interface. The issue I get since trying out the HibernateFilter is that Tomcat is unable to handle any requests (at all) while the consumer thread is processing. Originally, if you kicked off a consumer request Tomcat would hang when you try to hit it with another request but I was able to get it to the state it's in now by committing the transaction and closing the session.

Threads aren't really my forte, so if I've made some kind of schoolboy error please be gentle. I thought that, surely, since the consumer is running it its own thread it would have its own Session and Transaction. Does anyone have any idea why it would be causing Tomcat to hang until the Session/Transaction are closed? I kick off the consumer like this:

Code:
consumer = new Consumer();
consumerThread = new Thread(consumer);
consumerThread.setDaemon(true);
consumerThread.start();


This is a very sanitised version of my Consumer:

Code:
public class Consumer implements Runnable {

    private Queue queue;

    public Consumer() {
        queue = new LinkedList();
    }

    public void addRequest(Request request) {
        synchronized (queue) {
            queue.add(request);
            queue.notify();
        }
    }

    public void remove(Request request) {
        synchronized (queue) {
            queue.remove(request);
            queue.notify();
        }
    }

    public void run() {

        try {
            while (true) {
                synchronized (queue) {
                    while (queue.isEmpty()) {
                        queue.wait();
                    }
                }

                request = (Request) queue.poll();
                try {

                    // do some hibernate stuff
                    //

                } catch (Exception e) {

                    // handle the error
                    //

                } finally {
                    try {
                        HibernateSessionFactory.commitTransaction();
                        HibernateSessionFactory.closeSession();
                    } catch (HibernateException e) {
                        // this has been logged already
                        //
                    }
                }
            }
        } catch (InterruptedException e) {
            logger.warn(e);
        }
    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 05, 2006 5:04 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Even if it's doing nothing, that thread is going to try to use 100% of the CPU. It's not going to be allowed to, of course, but it's going to try.

To be nice, add a "Thread.yield()" at least once in every loop (top of the loop is best, in case you put in a "continue;" later and forget about the yield()).

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 06, 2006 4:06 am 
Regular
Regular

Joined: Tue Nov 23, 2004 7:42 am
Posts: 82
Location: London, England
tenwit wrote:
Even if it's doing nothing, that thread is going to try to use 100% of the CPU. It's not going to be allowed to, of course, but it's going to try.

To be nice, add a "Thread.yield()" at least once in every loop (top of the loop is best, in case you put in a "continue;" later and forget about the yield()).


Thanks for the suggestion but, unfortunately, it didn't help. It's strange because without closing the transaction/session the consumer never yields and Tomcat looks like it has hung.

I'll run it through the profiler and see if that can tell me anything.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 06, 2006 5:11 am 
Regular
Regular

Joined: Tue Nov 23, 2004 7:42 am
Posts: 82
Location: London, England
Interesting. The profiler shows the consumer as the only active thread while it's doing its thing. I added a few Thread.yield()s in a few places with no help. I'm wondering if I should be closing Hibernate sessions as I use them as this behaviour first came about when I started using a session per request rather than per database operation.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 06, 2006 5:46 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Aren't you already closing sessions as you use them? The close is inside the loop. Given how tight this loop is, it's likely that you'd get more performance benefit from reusing the session for even longer: perhaps you could add in a timer and logic to avoid closing the session more often than once per second or something, so that if you get 20 requests all at once, they'll all use the same session (separate transactions, of course).

I don't see anything else wrong with what you're doing. I think that more work with the profiler is probably required.

_________________
Code tags are your friend. Know them and use them.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 07, 2006 4:05 am 
Regular
Regular

Joined: Tue Nov 23, 2004 7:42 am
Posts: 82
Location: London, England
tenwit wrote:
Aren't you already closing sessions as you use them? The close is inside the loop. Given how tight this loop is, it's likely that you'd get more performance benefit from reusing the session for even longer: perhaps you could add in a timer and logic to avoid closing the session more often than once per second or something, so that if you get 20 requests all at once, they'll all use the same session (separate transactions, of course).

I don't see anything else wrong with what you're doing. I think that more work with the profiler is probably required.


No, I was using the HibernateFilter from Caveat Emptor to close the session and commit any transactions at the end of an HTTP request - so my DAOs don't explicity close any sessions.

I modified the consumer so that it would close sessions after a Hibernate operation. This solved the issue I had.

To be honest, this was more of an exercise in seeing how well our app would work if we did the Session-per-request pattern as we are wanting to use it in the next version. Prototyping if you will. This was the only issue I found but at least I have some kind of work-around.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.