简体   繁体   中英

How can a thread acquire lock on two objects simultaneously as in this case?

public void method(Type1 inst1, Type2 inst2) {
  synchronized(inst1) {
    synchronized(inst2) {
      //do something now
    }
  }
}

I can understand from this piece of code that once a thread enters the method, it acquires the lock on inst1, and then it acquires lock on inst2, without releasing inst1 lock. I assume that both of these objects are not locked by other thread.

  1. If a thread can acquire lock on only one object at once and can only own another lock when lock on current object has been released, how can this piece of code be valid, or rather, is it a valid code that I think I have seen somewhere?
  2. And what if Type1 and Type2 are same?
  3. What happens if we make the method synchronized, considering it resides in a class other than the parameter types of the method?

1 . If a thread can acquire lock on only one object at once and can only own another lock when lock on current object has been released, how can this piece of code be valid, or rather, is it a valid code that I think I have seen somewhere?

It is a valid code, the locks are not on the object where the method resides, but on inst1 and inst2 . Also, the lock is not on the class, but for every object

2 . And what if Type1 and Type2 are same?

again, the locks are on the objects, not on the classes. if inst1 and inst2 are the same, then the thread has only one lock, it is valid for the same thread to "re-enter" the lock

3 . What happens if we make the method synchronized, considering it resides in a class other than the parameter types of the method?

Then you have yet another lock, this time on the object (not the class) where the method is being executed.

由于@morgano@Nick霍尔特 ,我明白, 一个线程可以保持在同一时间多个锁 (不同的对象),或相同的对象上多次(使用获得的锁synchronized是隐含地折返)。

There is no problem with your code in case every time you need to obtain lock on those two objects you do it in the same order.

For example, if you have two methods

public void methodA(Type1 inst1, Type2 inst2) {
  synchronized(inst1) {
    synchronized(inst2) {
      //do something now
    }
  }
}

public void methodB(Type1 inst1, Type2 inst2) {
  //wrong
  synchronized(inst2) {
    synchronized(inst1) {
      //do something now
    }
  }
}

You have a potential deadlock problem as a thread could obtain the lock on inst1 and wait for the lock of inst2, while another thread have the lock on inst2 and wait for lock on inst1.

That code is very likely to result in a deadlock minefield, for sure.

The 2nd thread(threa2) that locks inst2 does not necessarily have to be running through methodA, but may lock object inst2 in another procedure, and does so before the thread1 in methodA, and then accesses method A and attempts to lock inst2, before releasing inst2. ahhhhh! boooom! :(.

suggested solution :
synchronize on methodA, and not on the objects , as that will lock all resources accessed in methodA() like so

public synchronized void methodA () {....}

Deadlocks happen when you acquire one lock inside another:

lock OB1 {
   lock OB2 { ... }
}    

because one could attempt to lock on a pair (1,2) and anther (2,1) . There are possible more lengthy chains: (1,2) + (2,3) + (3,1) .

You need to introduce order between locks to avoid deadlocks: Java synchronisation: atomically moving money across account pairs?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM