James, 

Whilst make the collection synchronized is definitely not an option (as 
explained by Steven in the same thread), making the missing methois that access 
the collection(s) in a write mode is a goal.

We'd definitely appreciate your help in this context, and the more of a test 
environment you have, the better for us and yourself.

Steven, shall we create a new Jira issue asking ourselves to have a look at 
this (making the remaining write methods thread-safe) ? 

Regards
Werner

> -----Ursprüngliche Nachricht-----
> Von: [EMAIL PROTECTED]
> [mailto:[EMAIL PROTECTED] Im Auftrag von James
> Gesendet: Mittwoch, 21. März 2007 13:50
> An: [email protected]
> Betreff: Re: Re: AW: AW: [castor-user] [XML] XMLClassDescriptorResolver
> XMLFieldDescriptorImpl cache possible memory leak
> 
> Hi All,
> 
> I've just joined the mailing list because I saw a conversation between
> Adam Chesney and the Castor development team in the archives, and
> thought I would add my two cents. :)
> 
> Below is a link to the last email on this thread:
> 
> http://archive.castor.codehaus.org/user/00b501c767ea%24da8a1880%240a84010a
> %40zultan
> 
> We use Castor in much the same way as Adam: 100's of thousands of Castor
> generated beans, and which get loaded at runtime depends very much on
> the user/runtime profile of our application. I agree with Adam that
> initialising the XMLClassDescriptorResolver at startup is not really a
> useful solution - we would have to maintain a very messy (and error
> prone) configuration to track individual bean classes in what is a huge
> application, and it would also cause unnecessarily high memory usage.
> 
> Although I can't be sure, looking at the source code for
> XMLClassDescriptorResolverImpl.DescriptorCache in Castor 1.1, I think
> changing the non-threadsafe collections to synchronized ones would
> probably do the trick. In any case, I'm sure making a thread-safe
> XMLClassDescriptorResolver implementation would not be that difficult
> and we will be more than happy to contribute codes and run some highly
> concurrent tests if the Castor developers agree that this is the best
> way forward.
> 
> My 2 cents!
> 
> Kind regards,
> 
>       James.
> 
> P.S. Below is a short investigation into the possible effects of using
> HashMap in a multi-threaded environment in a non-thread-safe way.
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> 
> As Adam's colleague has done, I have isolated the HashMap race condition
> (in both Java 1.4 and 1.5). The problem happens with concurrent writes
> to the map, no reads are necessary to recreate the problem (though they
> also have a race condition when there are concurrent writes).
> 
> Below is the source for HashMap.put:
> 
> <code>
> 
> public V put(K key, V value) {
>      if (key == null)
>          return putForNullKey(value);
>          int hash = hash(key.hashCode());
>          int i = indexFor(hash, table.length);
>          for (Entry<K,V> e = table[i]; e != null; e = e.next) {
>              Object k;
>              if (e.hash == hash && ((k = e.key) == key ||
> key.equals(k)))     {
>                  V oldValue = e.value;
>                  e.value = value;
>                  e.recordAccess(this);
>                  return oldValue;
>              }
>          }
> 
>          modCount++;
>          addEntry(hash, key, value, i);
>          return null;
>      }
> 
> </code>
> 
> As you can see, the for loop will only complete when "e != null" - that
> is to say, that the last entry in the table (Entry[]) is null. The call
> to HashMap.addEntry near the end of the method calls the HashMap.resize
> if the size of the array that backs the map needs to be resized. It
> seems that a circular reference inside one of the bins _can_ occur and
> _might_ cause a race condition. See the code for HashMap.transfer below:
> 
> <code>
> 
>   void transfer(Entry[] newTable) {
>          Entry[] src = table;
>          int newCapacity = newTable.length;
>          for (int j = 0; j < src.length; j++) {
>              Entry<K,V> e = src[j];
>              if (e != null) {
>                  src[j] = null;
>                  do {
>                      Entry<K,V> next = e.next;
>                      int i = indexFor(e.hash, newCapacity);
>                      e.next = newTable[i];
>                      newTable[i] = e;
>                      e = next;
>                  } while (e != null);
>              }
>          }
>      }
> 
> </code>
> 
> I am able to recreate the problem with the code below. If the HashMap is
> initialised to "maxSize", I have not seen the race condition occur,
> however, if it is initalised to 1 (as in the code below), the race
> condition happens relatively frequently.
> 
> <code>
> 
> /**
>   * HashMapTester
>   * Show a race condition HashMap
>   */
> public class HashMapTester{
> 
>      /**
>       * @param args
>       */
>      public static void main(String[] args) {
>         new HashMapTester().run();
>      }
> 
>      public void run() {
>          int max = 10;
>          int maxSize = 100000;
>          List<HashMapWriter> writers = new ArrayList<HashMapWriter>(max);
>          Map<String,String> m = new HashMap<String,String>(1);
>          for(int i = 0; i < max; i++) {
>              HashMapWriter writer = new HashMapWriter(m,maxSize);
>              writers.add(writer);
>              writer.start();
>              System.out.println("Num writers created: " + (i + 1));
>          }
>      }
> 
> 
>      class HashMapWriter extends Thread{
>          Random r = new Random(System.currentTimeMillis());
>          Map<String, String> m = null;
>          int maxSize =-1;
>          @Override
>          public void run() {
>              while(true) {
>                  if(m.size() < maxSize || m.size() == 0) {
>                      String something = String.valueOf(m.size());
>                      m.put(something,something);
>                      if(m.size() % 100 == 0) {
>                          System.out.println("Map size is now: " +
> m.size());
>                      }
>                  }else {
>                      String something =
> String.valueOf(r.nextInt(m.size()));
>                      m.put(something, something);
>                      try {
>                          Thread.sleep(r.nextInt(10) +1 );
>                      } catch (InterruptedException e) {
>                          e.printStackTrace();
>                      }
>                  }
> 
>              }
>          }
>          public HashMapWriter(Map<String, String> m, int maxSize) {
>              this.m = m;
>              this.maxSize = maxSize;
>          }
>      }
> }
> 
> </code>
> 
> ---------------------------------------------------------------------
> To unsubscribe from this list please visit:
> 
>     http://xircles.codehaus.org/manage_email


---------------------------------------------------------------------
To unsubscribe from this list please visit:

    http://xircles.codehaus.org/manage_email

Reply via email to