4

I'm wondering if there's a package or model that will help me solve this scenario.

Let's say I have 3 threads and a bunch of objects A,B,C,D,E,F

  • T1 needs locks A,B
  • T2 needs locks B,C,D
  • T3 needs locks E,F

In this scenario, it'd be ok if T1 & T3 ran simultaneously. Also, T2 & T3 can run simultaneously. But T1 & T2 should never run simultaneously.

Also, note that

  • Threads can obtain an arbitrary number of locks, not just 2. (I saw an elegant solution to this problem with a fixed number of locks but not sure I can apply it here.)
  • Obviously, I'd like each thread to acquire all the needed locks at the same time to prevent deadlock.

If someone can point me to a package that supports this use case, or some snippet of code that resolves this, please let me know.

Thanks so much.

kane
  • 5,465
  • 6
  • 44
  • 72
  • Are you sure you can't simplify this to require fewer concurrent locks? – Jon Skeet Feb 12 '14 at 20:40
  • This sounds awfully complicated and error-prone, but look at [java.util.concurrent.locks](http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/package-summary.html). – vanza Feb 12 '14 at 20:43
  • I think you can avoid deadlock by ensuring that you always acquire B before A or C+D and always release C+D or A before releasing B. – aebabis Feb 12 '14 at 20:44
  • 2
    The scenario you presented can't possibly lead to deadlock. There are no cycles. – Rainbolt Feb 12 '14 at 20:46
  • Unfortunately, this is the scenario. The lock objects are IDs of thousands of "things" in the system. Threads will work on groups of these things at the same time and there's no guarantee which things or how many will be worked on – kane Feb 12 '14 at 21:16
  • @acbabis I might be able to acquire locks in order. Does that solve my issue altogether? – kane Feb 12 '14 at 21:19
  • @kane John's solution is indeed the correct solution as long as you can call all your locks sequentially at the beginning of your routines. Assuming you have all the ID's for a thread up front, you need to sort them alphanumerically and then lock them in order. If you don't have all the ID's when you begin processing, I believe I have a (ugly) solution for that problem. – aebabis Feb 12 '14 at 21:39

2 Answers2

5

Step 1

Provide a natural ordering for your resources. For example, if your resources were letters, A would come before B, B would come before C, and so on.

Step 2

Only allow your threads to grab resources in order.

Now your threads cannot possibly reach deadlock in any situation.

Example

  • Thread 1 needs locks on resources A, B, D, and E
  • Thread 2 needs locks on resources B and E

Our threads must fight for locks on resources B and D. Because we have enforced a natural order, the thread that obtains the lock on B first is guaranteed to get the lock on D and proceed smoothly. The losing thread will be waiting for B to be released.

Rainbolt
  • 3,542
  • 1
  • 20
  • 44
  • I think this is the answer as you and acbabis mentioned in the comments. Let me think about it some more and make sure I can acquire the resources in order. I'll come back and accept this answer once I gather investigate further – kane Feb 12 '14 at 21:21
  • The ordering does not have to exist. If you put random things into an array, that *becomes* your order. You only have to enforce your order. When each thread goes to acquire locks, make it acquire them sequentially. They will sleep automatically if they reach one that is locked. If they don't, you're not using the right kind of lock. – Rainbolt Feb 12 '14 at 22:17
  • 1
    What if 2 objects are "equal" in terms of ordering? E. g. have the same hash code? – Alex Salauyou Apr 20 '15 at 13:44
  • 1
    @SashaSalauyou If two objects are equal, then they had better be the same object. An object cannot deadlock with itself. If the two objects are not the same, then your natural ordering is flawed, and you need to provide a better one. – Rainbolt Apr 20 '15 at 19:41
2

To avoid deadlock in these scenarios you must need to induce an ordering on the locks and acquire them according to the induced ordering consistently though out your application.

I understand this answer has been mentioned and may be sufficient in particularly your case but natural ordering is possible only when objects are comparable :(

Best way to induce ordering on objects is to use the System.identityHashCode(A/B/C...lock object) which returns value of hashcode. But again don't feel 100% safe as you might be victim of hash collision and even the chance is rare but you might get Deadlock. In those scenarios you need additional safety in your code. Your make your threads to compete for some separate 'tie breaking' lock. Hope this information helps in getting a bit more clear picture on your problem.

Mak
  • 596
  • 5
  • 10