"Concurrent operations are often more complex than the concurrent design[...]"
should be "Concurrent operations are often more complex than the >current< design" :-) Eric -----Original Message----- From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]] Sent: Thursday, December 19, 2002 4:26 PM To: [EMAIL PROTECTED] Subject: RE: Q. about equals() in WSDL generated datatypes Two options come to mind: 1. remove synchronization and document the issue so that people using these objects in a multi-threaded situation are aware that they need to use an external mutex lock to get thread safety without deadlock. In a word, punt. 2. make _equalsCalc a static java.lang.ThreadLocal instance, and lock on the per-thread instances managed within that ThreadLocal. This is a variation on your "make _equalsCalc a static synchronized singleton" idea, except that it allows threads to run concurrently, each with its own _equalsCalc state machine across recursive calls. My preference would be for #1 for the following reasons: 1. In most cases, users are not generating deeply self-referential object graphs. 2. In most cases, uses are not doing concurrent equals() tests. It will happen, but not as frequently as single threaded access. 3. Concurrent operations are often more complex than the concurrent design allows. That is, a user who wants to take an action based on the equality of an object graph to another object graph *usually* wants to ensure that one or the other of those graphs do not change in between the time that s/he invokes object.equals(other) and the time that s/he invokes the action resulting from their being proven equal. Consider: if (A.equals(B)) { // do something } else { // do something else } I need a coarser lock on *both* A and B if I care about atomicity within the operations on either side of the equals() decision here. Synchronizing on A alone does not help me achieve this. Note that this is one of the reasons that the Java 2 Collections API no longer synchronizes methods (the way Hashtable and Vector did) -- locks at the level of granularity are necessary, but not sufficient to tasks like one described above. 4. Option #2 is not free, and it doesn't seem right to impose those costs on single-threaded users and/or on users who need more sophisticated locking schemes anyway (for the reasons stated above). Eric -----Original Message----- From: R J Scheuerle Jr [mailto:[EMAIL PROTECTED]] Sent: Thursday, December 19, 2002 3:45 PM To: [EMAIL PROTECTED] Subject: RE: Q. about equals() in WSDL generated datatypes Good points. So what kind of solution do you propose. Eliminating synchronization would lead to __equalsCalc being corrupted in a multi-threaded situation. Keeping synchronization could lead to deadlock. But if the __equalsCalc state information is eliminated completely, there will be an infinite loop problem and incorrect behavior. I also want to point out the eliminating the equals() method and reverting to Object.equals will break the tests. The only solution is to make __equalsCalc a singleton static item in the system and synchronize on it. This would cause all generated equals logic to wait.... Comments. Rich Scheuerle IBM WebSphere & Axis Web Services Development 512-838-5115 (IBM TL 678-5115) Eric.D.Friedman@Wel lsFargo.COM To: [EMAIL PROTECTED] cc: 12/19/2002 04:14 PM Subject: RE: Q. about equals() in WSDL generated datatypes Please respond to axis-dev I'm not Stephen, but I'd like to join this thread, as I think there's a more subtle problem here: // Stephen pointed out that we can never recurse back // because the method is syncronized... // or does syncronization know that I am recursing back // in the same thread. The lock on the object with the synchronized method belongs to your thread, so yes, it's possible to call a synchronized method recursively from within a single thread, just as it's possible to invoke other synchronized methods on that same object. There's a bigger problem here, however: synchronizing equals() methods in this manner could result in thread deadlock if the objects in question are deeply self referential. Look at the calls to exchange.equals() and number.equals() in the code below. Now imagine that number has a backreference to Phone and so its equals() method needs to invoke Phone.equals() for the same reason that Phone's equals() method needs to invoke number.equals(). Further suppose that two threads are active: one invokes Phone.equals() while the other one calls number.equals() for some other purpose. Both threads will be deadlocked, since neither equals() method can terminate until the other relinquishes the lock. This is a danger inherent in code generation of this kind, and I suggest that the right thing to do is to leave synchronization to the user of the object -- it's just not possible (read: too expensive) to adequately handle all of the cases that a tool like wsdl2java would have to deal with. My unsolicited 2 cents, Eric -----Original Message----- From: R J Scheuerle Jr [mailto:[EMAIL PROTECTED]] Sent: Thursday, December 19, 2002 1:46 PM To: [EMAIL PROTECTED] Subject: RE: Q. about equals() in WSDL generated datatypes Here's the full annotated code (for Phone). I think the bug is that __equalsCalc must be be reset before returning. So I marked this as red. Please evaluate and send me your comments. Also think of the equals evaluating to different linked lists that contain the same data. Lets assume A1->A2->A3 equals B1->B2->B3 Now change the above slightly so the linked lists are circular. A1->A2->A3 equals B1->B2->B3 ^-------+ ^--------+ They are still the same, and the equals method should return true. This is the case handled by __equalsCalc == obj Now change the linked lists in a more devious way. A1->A2->A3 equals B1->B2->B3->A1->A2->A3 ^-------+ ^-------------------+ In this situation, the equals method should return false since the looping is different. In the first case, the third object points back to the initial object. In the second case, the third element points to an object other than the initial object. This is the case handled by __equalsCalc != obj. private java.lang.Object __equalsCalc = null; public synchronized boolean equals(java.lang.Object obj) { // Return false immediately if wrong types if (!(obj instanceof Phone)) { __equalsCalc = null; return false;} // Return false if other object is null Phone other = (Phone) obj; if (obj == null) { __equalsCalc = null; return false; } // Return true if == if (this == obj) { __equalsCalc = null; return true; } // if equalsCalc is set, then we have looped // back to the "this" object. Since the last time through // we set _equalsCal to the other object, return // true if the equalsCalc == the other object (the // the other object loops the same way) or return // false if the equalsCalc != the other object (the other // object does not loop the same way.) // Stephen pointed out that we can never recurse back // because the method is syncronized... // or does syncronization know that I am recursing back // in the same thread. if (__equalsCalc != null) { boolean rc = (_equalsCalc == obj); __equalsCalc = null; return rc; } // Flow to here indicates no recursion, so set _equalsCalc // to the other object in-case recursion occurs in the following code. __equalsCalc = obj; boolean _equals; _equals = true && areaCode == other.getAreaCode() && ((exchange==null && other.getExchange()==null) || (exchange!=null && exchange.equals(other.getExchange()))) && ((number==null && other.getNumber()==null) || (number!=null && number.equals(other.getNumber()))); // Always reset __equalsCalc before returning. __equalsCalc = null; return _equals; } Rich Scheuerle IBM WebSphere & Axis Web Services Development 512-838-5115 (IBM TL 678-5115) Glen Daniels <gdaniels@macrome To: "'[EMAIL PROTECTED]'" <[EMAIL PROTECTED]> dia.com> cc: Subject: RE: Q. about equals() in WSDL generated datatypes 12/19/2002 07:59 AM Please respond to axis-dev Hi Rich! Hm - I'm trying to imagine an example for when this would actually get used, and having trouble coming up with one. Could you elucidate? I guess what I'm really asking is why doesn't "if (this == obj) return true" catch this? --G P.S. Nice to see you back! > -----Original Message----- > From: R J Scheuerle Jr [mailto:[EMAIL PROTECTED]] > Sent: Wednesday, December 18, 2002 8:27 PM > To: [EMAIL PROTECTED] > Subject: Re: Q. about equals() in WSDL generated datatypes > > > > Yes __equalsCal was meant to support equals for objects that > had direct or > indirectly references back to the object. > > Rich Scheuerle > IBM WebSphere & Axis Web Services Development > 512-838-5115 (IBM TL 678-5115) > > > > > "Steve Loughran" > > <[EMAIL PROTECTED] To: > "axis-dev" <[EMAIL PROTECTED]> > om> cc: > > Subject: Q. > about equals() in WSDL generated datatypes > 12/18/2002 02:38 > > PM > > Please respond to > > axis-dev > > > > > > > > > > So I'm staring at the equals() method that's been generated > for me from a > datatype > > private java.lang.Object __equalsCalc = null; > > public synchronized boolean equals(java.lang.Object obj) { > if (!(obj instanceof JobInfo)) return false; > JobInfo other = (JobInfo) obj; > if (obj == null) return false; > if (this == obj) return true; > if (__equalsCalc != null) { > return (__equalsCalc == obj); > } > __equalsCalc = obj; > ...tests > __equalsCalc = null; > return _equals; > > > My q. is: what is all this __equalsCalc stuff? It implies > that if there is > a > reentrant equality test then the test would return true while > the test is > ongoing, but since the method is synchronized, you'd be hard > pressed to > call > equals() twice. > > Is that what the __equalsCalc is there for? To catch recursion? > > -steve > > > > >