0

I'm facing a problem in an application where two threads with same parameters are run, a conflict occurs. One solution was to use a synchronized block, but since the problem occurs only for threads with same params, it would be highly inefficient. One way I thought of was to use a concurrent map to store the param combination as key and an object as value, whenever a thread begins the operation it first checks if the map contains the key (param combination) and if so, it will do a wait on the object stored for that combination. The thread would at the end remove this object from the map and invoke notify on it. The problem with this approach is generating the same object for the same param combination. For ex: if thread1 inserts into map, and calls notify and removes it, thread2 may come out of wait, but other threads will never come out as the object is lost from the map.

Is there a different elegant approach to this problem?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
Rnet
  • 4,796
  • 9
  • 47
  • 83
  • 1
    Why does the conflict only happen when they are run with the same parameters? Could you post your code? – Vala Oct 28 '11 at 11:37
  • @Thor84no the problem is an old code which I'm maintaining, http://stackoverflow.com/questions/7888764/java-selective-synchronization – Rnet Oct 28 '11 at 11:38
  • 2
    So, let me get this straight. You've already asked this question before, you got some decent answers that have been voted highly, made no effort to say why these don't solve your problem and you expect to get a better result this time? – Vala Oct 28 '11 at 11:41
  • @Thor84no No , If you see that thread closely, the highly voted solutions suggest taking the operation to the db, which I could've done before asking that question, the reason I asked is not to change the pre existing code, and come up with a work around using threads. What I hoped to get from this question was to know if a different approach existed other than the wait, notify etc – Rnet Oct 28 '11 at 11:49
  • I did read the thread closely and you never said anything about why that wasn't good enough for you. The fact of the matter is they're probably right and that *is* the best solution. So when you don't respond to it, how do you expect to get a better alternative? What you should have done is tell them you didn't want to do it in the database, and your reasons for that in that question rather than open a new one. – Vala Oct 28 '11 at 11:56
  • @Thor84no Fine, that may've been the right thing to do. I just thought I'll abstract the problem only to threads and see if different approaches existed using functionalities in java.util.concurrent – Rnet Oct 28 '11 at 12:04
  • http://stackoverflow.com/questions/5639870/simple-java-name-based-locks/5640671#5640671 – irreputable Oct 28 '11 at 13:08

3 Answers3

0

Create a pool of parameter combinations. Every time you need to guarantee one thread is running, call Pool.acquire(params).

Use it like this:

Wrap parameters in an object with nice hashCode and equals.

In Thread:

synchronized(pool) {
  pool.acquire(myParams);
}
// do the work
synchronized(pool) {
  pool.release(myParams);
}

Pool:

class Pool {
  Set<Params> lockedParams;

  // In Pool - note that this is synchronized!
  void acquire(Params params) {
    Params lock = lockedParams.get(params);
    if(lock != null) {
      // Locked by another thread
      lock.wait();
    }
    lockedParams.add(params);
  }

  void release(Params params) {
    Params lock = lockedParams.remove(params);
    lock.notifyAll();
  }
}

That's one idea. You need to add some error handling for real life cases (release() in finally, in this case handle null lock in Pool.release(), etc.).

Konrad Garus
  • 53,145
  • 43
  • 157
  • 230
  • How does this allow multiple threads inside your `synchronized(pool)` block (where the work is done) when they have different parameters? – Vala Oct 28 '11 at 11:46
  • I think the idea is a thread pool that allows only unique Params to have concurrent threads. If a duplicate Params tries to acquire a Thread, it blocks until the currently executing (duplicate) Params completes. It looks to me like it may have some problems as you suggest, i.e. if you wait() in acquire() then no other threads can be acquired from the pool - duplicate Params or not. I'm sure the scheme could be implemented differently so that it would work though. – sceaj Oct 28 '11 at 21:24
  • `wait()` releases all monitors, and they are reacquired when the thread wakes up. I think Thor84no was referring to an older version where both `acquire()` and `release()` were wrapped in a single `synchronized` block – Konrad Garus Oct 29 '11 at 06:12
0

Call notifyAll instead of notify, so all waiting threads will be notified. And why do you want to remove sync object from map? Just try to acquire lock on that object, if thread succeeds, it enters critical section, otherwise it starts to wait.

You can add timeout to that wait, so if thread can't acquire lock for some period, it fails. This way your code won't go into deadlock.

Victor Sorokin
  • 11,878
  • 2
  • 35
  • 51
0

If you can represent the parameters (or a subset of them) as a String, you can synchronize on the interned string.

forty-two
  • 12,204
  • 2
  • 26
  • 36