破译 OSGi 代码段中的死锁情况
Decipher a deadlock situation in an OSGi code piece
下面这段代码是为了演示一段OSGi代码中可能发生的死锁,直接取自免费下载的书籍:osgi in practice (Neil Bartlett)。这本书通常很容易理解,我发现它非常有用。但是,我不确定我是否遵循了第 130 页中确定的(并略微讨论过的)并发问题。代码如下:
package org.osgi.book.reader.dbmailbox;
public class BadLockingMailboxRegistrationService implements MailboxRegistrationService {
private final Map<String,ServiceRegistration> map =
new HashMap<String,ServiceRegistration >();
private final BundleContext context ;
public BadLockingMailboxRegistrationService(BundleContext context) {
this . context = context ;
}
// DO NOT DO THIS!
public synchronized void registerMailbox ( String name, Mailbox mailbox){
ServiceRegistration priorReg = map.get(name);
if(priorReg != null) priorReg . unregister ();
Properties props = new Properties ();
props.put(Mailbox.NAME_PROPERTY , name);
ServiceRegistration reg =
context . registerService (Mailbox.class.getName(), mailbox , props );
map . put(name , reg );
}
}
提供的讨论是如何发生死锁的:
To translate this unhappy situation to OSGi programming, imagine that
a thread has taken a lock on an object F. Then it tries to call our
register- Mailbox, which locks object K — but it must wait, perhaps
because another thread is already executing registerMailbox. One of
the callbacks resulting from the service registration then attempts to
lock F . The result: two starving threads and no work done.
我理解讨论的第一部分,即线程可能锁定对象 F,它试图调用 registerMailbox,从而锁定对象 K (其中 K 是为此特定服务注册的服务对象,我认为是这样!)。现在确定,另一个线程已经在执行 registerMailbox。这意味着,它还需要锁定 K(因为 OSGi 分发一个单例服务对象)。现在讨论的回调在哪里,它可能试图锁定 F,从而导致死锁?
作者注意到 context.registerService
在执行期间通知侦听器在同一线程上进行服务注册。如果这些侦听器中的一个依次尝试获取锁 F
,它将导致死锁,因为 F
被同时持有 K
.
的线程持有
线程 2:调用 registerMailbox
并获取 K
线程 1:在调用 registerMailbox
之前获取 F
,然后调用同步的 registerMailbox
,因此尝试获取 K
但由于它被线程持有而阻塞2
线程 2:最终执行 context.registerService
,后者又调用试图获取 F
的 listener/callback,并阻塞,因为它被线程 1
持有
由于有两个线程以相反的顺序获取了两个锁,并且每个线程都获取了其中一个而没有获取第二个,因此发生了死锁。这并不是一个特定于 OSGI 的问题,但我想说明了服务注册涉及侦听器通知,应该在谨慎持有锁时调用。
下面这段代码是为了演示一段OSGi代码中可能发生的死锁,直接取自免费下载的书籍:osgi in practice (Neil Bartlett)。这本书通常很容易理解,我发现它非常有用。但是,我不确定我是否遵循了第 130 页中确定的(并略微讨论过的)并发问题。代码如下:
package org.osgi.book.reader.dbmailbox;
public class BadLockingMailboxRegistrationService implements MailboxRegistrationService {
private final Map<String,ServiceRegistration> map =
new HashMap<String,ServiceRegistration >();
private final BundleContext context ;
public BadLockingMailboxRegistrationService(BundleContext context) {
this . context = context ;
}
// DO NOT DO THIS!
public synchronized void registerMailbox ( String name, Mailbox mailbox){
ServiceRegistration priorReg = map.get(name);
if(priorReg != null) priorReg . unregister ();
Properties props = new Properties ();
props.put(Mailbox.NAME_PROPERTY , name);
ServiceRegistration reg =
context . registerService (Mailbox.class.getName(), mailbox , props );
map . put(name , reg );
}
}
提供的讨论是如何发生死锁的:
To translate this unhappy situation to OSGi programming, imagine that a thread has taken a lock on an object F. Then it tries to call our register- Mailbox, which locks object K — but it must wait, perhaps because another thread is already executing registerMailbox. One of the callbacks resulting from the service registration then attempts to lock F . The result: two starving threads and no work done.
我理解讨论的第一部分,即线程可能锁定对象 F,它试图调用 registerMailbox,从而锁定对象 K (其中 K 是为此特定服务注册的服务对象,我认为是这样!)。现在确定,另一个线程已经在执行 registerMailbox。这意味着,它还需要锁定 K(因为 OSGi 分发一个单例服务对象)。现在讨论的回调在哪里,它可能试图锁定 F,从而导致死锁?
作者注意到 context.registerService
在执行期间通知侦听器在同一线程上进行服务注册。如果这些侦听器中的一个依次尝试获取锁 F
,它将导致死锁,因为 F
被同时持有 K
.
线程 2:调用 registerMailbox
并获取 K
线程 1:在调用 registerMailbox
之前获取 F
,然后调用同步的 registerMailbox
,因此尝试获取 K
但由于它被线程持有而阻塞2
线程 2:最终执行 context.registerService
,后者又调用试图获取 F
的 listener/callback,并阻塞,因为它被线程 1
由于有两个线程以相反的顺序获取了两个锁,并且每个线程都获取了其中一个而没有获取第二个,因此发生了死锁。这并不是一个特定于 OSGI 的问题,但我想说明了服务注册涉及侦听器通知,应该在谨慎持有锁时调用。