Win a copy of The Java Performance Companion this week in the Performance forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

How Iterate Synch'd List of Connections and close them?

 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a synchronized list of connections. I want to iterate through that list and close them all. However, it always throughs a java.util.ConcurrentModificationException even though I follow the rules in the java.sun.com tutorial:

It's the con.close() that causes the problem. When I move to the next item in the list, it throws the exception. Does anyone know how I can do this?
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here's something else weird:
I print out the size of my list and it's 1!! So why is it trying to come back in to the list? Here's something else weird:
When I dod NOT close the connection, it does NOT come back in to the while loop. BUT if I close the connection, the while loop will continue around again. Why is this?
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, figured out something here:
If I remove the connection from the list first and THEN close it, there's no problem!
So I'm guessing that closing it somehow sets it null (?) which then removes it from the list without changing the size of the list (?) making it think there's still another item in the list? Does any of this sound remotely correct?
I've seen other people with code that closes the connection first then removes it - do they have bad code (and they just haven't hit the exception yet) or am I just doing something wrong here?
[ February 27, 2003: Message edited by: Dan Bizman ]
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My guess is that somewhere you've got other code which is accessing idleConnections without using synchronization. This would mean that even though you synchronized the loop shown above, it doesn't matter since the other code simply ignores the synchronization. Why is this a problem when you close() first, but not if you remove the item from the Collection before closing? My guess is that close() is a time-intensive operation. When you finish with the collection before closing, you minimize the time between acquiring the Iterator and calling remove(). This minimizes (but not eliminates) the chance that another thread will modify the collection while you're still iterating. But if you call close() before remove(), you greatly increase the chance for the other thread to interfere with your iteration.
Based on this theory, you really need to find the other code that accesses the idleCollection without proper synchronization. Moving the close() method improves your chances of avoiding a problem, but does not guarantee you'll be OK. Furthermore if idleCollection ever has more than 1 Connection in it, your chances of ConcurrentModificationException will increase substantially, no matter where the close() has been moved.
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
But that's impossible (I think) because it's in a shutdown hook. Also, I have all my code logging what it's doing and before it hits the shutdown hook, everything else is quiet and all the connections closed. Yet, it still throws this error. Any ideas?
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I GOT IT!!! I GOT IT!!! And you're not going to believe this! My PoolManager test was using the MySQL ConnectionPoolDataSource:
com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
Well, turns out they actually coded it backwards! See they use the same method to send an error event as a closed event, but the only way they distinguish is by an int which is either 1 or 2. Well, 2 means an error occurred and they mis-coded the close() method to send 2 instead of 1. So THAT is why I couldn't close the stupid thing and it kept throwing that problem! (So I recompiled their code, added it to the jar file and it works! Man what a BIG mistake in released code! how come no one ever noticed that?)
Now it DID make me see a problem with my code - I was not synchronizing the removal in my error-handling code. So now I have a question:
Let's say an error is thrown when I try to close it, it will call my event listener which, if in a synchronized call, I assume will wait for the first which is waiting for that - deadlock. So what's the solution? (The listener is the same class/object as the one that is trying to close everything)
 
karl koch
Ranch Hand
Posts: 388
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi

closing the connection can not set it to null and remove it from the list. it would need to assign null to your reference (con = null).
i agree with jim, there must be somebody else touching (adding/removing stuff) the idleConnections list. as an addition: close the connection in a try/catch block to make sure all connections are closed even if one close() operation throws an exception.
k
 
Dan Bizman
Ranch Hand
Posts: 387
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OK, I'm confused because here's what happens:
1. synchronize block started on idleConnections
2. Inside block, I call close() on the conn
3. The close call throws error (because of bad MysqlPooledConnection code)
4. the error causes my object's event listener interface to be called (connectionErrorOccurred)
5. Inside the connectionErrorOccurred method, I start a synchronized block on idleConnections
6. In that block I remove the bad connection
7. It returns to the first method, still inside the block and tries to remove and gets an error
Why is this happening? They're both in a synchronized block, shouldn't the first block the second from being able to get inside it's block? Is it because it's in the same thread?
[ February 27, 2003: Message edited by: Dan Bizman ]
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is it because it's in the same thread?
Yup. A lock for a given monitor can be acquired multiple times by code run by a single thread - it just can't be acquired by a different thread until the original thread releases it. If a lock has been acquired n times, it must also be released n times before it's available to other threads.
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic