public void method(Type1 inst1, Type2 inst2) {
synchronized(inst1) {
synchronized(inst2) {
//do something now
}
}
}
我可以从这段代码中理解,一旦线程进入方法,它就获取inst1上的锁,然后它获取inst2上的锁,而不释放inst1锁。我假设这两个对象都没有被其他线程锁定。
1。如果一个线程一次只能锁定一个对象,并且当当前对象的锁定被释放时只能拥有另一个锁,那么这段代码怎么可能有效,或者更确切地说,它是一个有效的代码,我认为我已经看到了某处?
它是一个有效的代码,锁不在方法所在的对象上,而是在inst1
和inst2
上。此外,锁不在类上,而是在每个对象上
2。如果Type1和Type2相同怎么办?
再次,锁在对象上,而不在类上。如果inst1和inst2相同,那么该线程只有一个锁,它对同一个线程有效“重新进入”锁
3。如果我们使方法同步,会发生什么情况,考虑到它位于方法的参数类型以外的类中?
然后你还有另一个锁,这次是在执行方法的对象(不是类)上。
感谢@morgano和@Nick Holt,我理解一个线程可以同时拥有多个锁(不同的对象),或多次同一个对象(使用synchronized
获得的锁是隐式重入的)。
如果您需要以相同的顺序对这两个对象进行锁定,则代码没有问题。
例如,如果您有两种方法
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
}
}
}
你有一个潜在的死锁问题,因为一个线程可以在inst1上获得锁定并等待inst2的锁定,而另一个线程在inst2上有锁定并等待inst1上的锁定。
那个代码肯定会导致死锁雷区。
锁定inst2的第二个线程(threa2)不一定必须通过methodA运行,但可以在另一个过程中锁定对象inst2,并在methodA中的thread1之前执行,然后在释放之前访问方法A并尝试锁定inst2 INST2。 AHHHHH! boooom! :(。
建议解决方案 在methodA上同步,而不是在对象上,因为这将锁定在methodA()中访问的所有资源,就像这样
public synchronized void method(){....}