You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jcs-dev@jakarta.apache.org by Hanson Char <ha...@gmail.com> on 2005/01/25 06:49:31 UTC

FooBar 1.5 Concurrency

Imagine a system which has only 2 types of operations {foo, bar} on
different keys, and must obey the following rules:

1) Concurrent foo's are allowed on the same key;
2) Concurrent bar's are allowed on the same key;
3) If foo and bar are concurrent on the same key, then
   a) if foo happens before bar, bar must wait for all foo's in
progress to complete before proceeding;
   b) if bar happens before foo, foo must abort.

I have the following code to try to achieve/illustrate the above.  Is
there any simpler/better/faster way to do it ?  Any way to avoid the
synchronized block altogether ?  Or any utility classes I may use to
reduce the complexity ?

Thanks in advance,
Hanson

public enum FooBarType {
   FOO,
   BAR;
}

public class FooBar {
   ConcurrentMap<String, FooBarType[]> synMap =
           new ConcurrentHashMap<String,FooBarType[]>();

   public void foo(String key) {
       FooBarType[] lock = {FooBarType.FOO};
       FooBarType[] otherLock = null;

       synchronized(lock) {
           otherLock = synMap.putIfAbsent(key, lock);

           if (otherLock == null) {
               // no concurrent foo nor bar on the same key, so doFoo.
               this.doFoo(key);
               synMap.remove(key); // release lock.
               return;
           }
       }
       // Race condition:
       // either a FOO or BAR is being done on the same key at the same time.
       switch(otherLock[0]) {
           case FOO:
               System.out.println("Concurrent foo on the same key: proceed.");
               this.doFoo(key);
               return;
           case BAR:
               System.out.println("Concurrent bar on the same key: abort.");
               return;
       }

   }
   public void bar(String key) {
       FooBarType[] lock = {FooBarType.BAR};
       FooBarType[] otherLock = synMap.putIfAbsent(key,  lock);

       if (otherLock == null) {
           // No concurrent foo nor bar, so doBar.
           this.doBar(key);
           synMap.remove(key); // release lock
           return;
       }
       // Race condition:
       // either a FOO or BAR is being done on the same key at the same time.
       switch(otherLock[0]) {
           case FOO:
               do {
                   // Wait till all FOO's are finished.
                   synchronized(otherLock) {
                       otherLock = synMap.putIfAbsent(key,  lock);
                   }
               } while (otherLock != null && otherLock[0] == FooBarType.FOO);

               if (otherLock == null) {
                   // no concurrent FOO nor BAR.
                   this.doBar(key);
                   synMap.remove(key); // release lock
                   return;
               }
               // Must be a concurrent BAR.
               // drop thru.
           case BAR:
               // Concurrent BAR.
               this.doBar(key);
               return;
       }
   }
   private void doFoo(String key) {
       System.out.println("doFoo must be only invoked when there is
no concurrent doBar on the same key.");
   }
   private void doBar(String key) {
       System.out.println("doBar must be only invoked after all
concurrent Foo's are finished on the same key.");
   }
}

---------------------------------------------------------------------
To unsubscribe, e-mail: turbine-jcs-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: turbine-jcs-dev-help@jakarta.apache.org