0

I have a use case like this. One of my method takes a List as parameter. I need to protect the critical section if and only if atleast one of the object is already locked by some other thread. How can achieve using java.util.concurrent package? I can think of simple HashTable based solution, something like

class ContainsCriticalSections {
    HashTable<SomeObject, Thread> map; //shared by multiple threads

    someCriticalMethod(List<SomeObject> objects) {
        acquireLocks(objects);
        //do critical task
        releaseLocks(objects);
    }

    synchronized acquireLock(List<SomeObject> objects) {
        bool canLock = false;
        while (!canLock) {
               for (SomeObject obj : objects) {
                   if (!map.contains(obj)) {
                       canLock = true;   
                   }
                   else if(map.get(obj).equals(Thread.currentThread())) {// ensuring re-entrace
                       canLock = true; 
                   }
                   else {
                       canLock = false;    
                   }
               }
               if (!canLock) {
                   wait();
               }
        }
        for (SomeObject obj : objects) {
                   map.put(obj, Thread.currentThread());
        }   

    } 

    synchronized releaseLock(List<SomeObject> objects) {
            for (SomeObject obj : objects) {
                   map.reomve(obj);
            }
            notify();
    }

  }

So in the above case if two invocations with A,B,C and D, E, F don't block. But, A, B, C and A, E, F will block.

but, I strongly feel there will some established paradigm here (using java.util.Concurrent).

Gopal
  • 1,292
  • 3
  • 19
  • 41

2 Answers2

1

You need to acquire all the locks, otherwise even if when you were entering critical section nobody was holding any locks, somebody may acquire one while you are inside. Here is method that can be used to run task under several locks:

public static void runUnderMultipleLocks (Runnable task, Object ... monitors)
{
    runUnderMultipleLocks (task, 0, monitors);
}

private static void runUnderMultipleLocks (Runnable task, int offset, Object ... monitors)
{
    if (offset == monitors.length) task.run ();
    else
    {
        synchronized (monitors [offset])
        {
            runUnderMultipleLocks (task, offset + 1, monitors);
        }
    }
}
Mikhail Vladimirov
  • 13,572
  • 1
  • 38
  • 40
1

I suspect you are looking for a ReadWriteLock. See ReentrantReadWriteLock for an example.

A ReadWrite lock allows multiple concurrent Read locks but any attempt to obtain a Write lock will block until all locks (Read or Write) have been released.

So your method that takes the List should request a Write lock while all of the others request Read locks.

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
  • @OldCurmudgeon...Thanks for the info about ReadWriteLock. But, it wouldn't suit my purpose. What I'm trying to achieve is typical critical section protection. – Gopal Feb 07 '13 at 10:51
  • @Gopal - What do you mean by `Typical`? My interpretation of your code looks very much like a `ReadWrite` lock to me. – OldCurmudgeon Feb 07 '13 at 11:55
  • @OldCurmudgeon...sorry for being unclear. What I meant was, the critical section I mentioned above contains only write operations and are not thread safe. Imagine I want to update (readAndIncrement) objects A,B,C (in a single batch) and D,E,F (in a single batch) in a cache. If thread1 tries to update A,B,C and thread2 tries to update D,E,F there are no issues and there is no point in one thread waiting for other to finish. However, if thread1 tries to update A,B,C and thread2 tries to update A,D,E, then, there is a problem and the calls should be serialized. – Gopal Feb 07 '13 at 13:25
  • @Gopal - Ah! I see. It sounds like you need a separate Read/Write lock for each. Perhaps you could consider any of the [ConcurrentMap](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentMap.html)s? – OldCurmudgeon Feb 07 '13 at 14:42