【问题标题】:Thread acquires ReentrantLock which is already acquired by other thread线程获取了已经被其他线程获取的 ReentrantLock
【发布时间】:2015-09-04 09:01:00
【问题描述】:

我们的应用程序在 WebLogic 12c 中运行,正在从队列系统中检索消息,我们从中检索消息的队列被配置为 FIFO。我们使用 Spring 来配置检索功能,并且容器 (org.springframework.jms.listener.DefaultMessageListenerContainer) 和消息侦听器 (org.springframework.jms.core.support.JmsGatewaySupport) 都是单例的。此外,该容器默认配置了一个 WorkManager 作为任务执行器。为了保证消息按照预期的顺序(它们发送到队列的顺序)进行处理,我们在监听器中使用了 ReentrantLock,我们期望消息被一一检索和处理。监听代码如下:

public class JmsReceiveAdapterImpl extends JmsGatewaySupport implements SessionAwareMessageListener {
    private final ReentrantLock lock = new ReentrantLock(true);
    [...]
    public void onMessage(Message rcvMessage, Session session) throws JMSException {
        lock.lock();
        logger.warn("Lock has been acquired by thread: " + Thread.currentThread().getId());
        try {
            [...]
        } finally {
            logger.warn("Lock is going to be released by thread: " + Thread.currentThread().getId());
            lock.unlock();
        }
    }
}

即使两条消息以正确的顺序放置在队列中,并且它们按该顺序被使用(回想一下队列是一个 FIFO 队列),但不知何故,这两条消息由应用程序并行处理,如图所示在以下日志块中:

锁已被线程获取:28 退出计数:1 从 XXX 收到的消息 1 / 1 收到消息 ID1。 锁已被线程获取:54 退出计数:1 从 XXX 收到消息 ID2 收到的消息 1 / 1。 ***** 错误 ***** 锁将被线程释放:54 锁将被线程释放:28

为什么我们会获得这种行为?有什么想法吗?

非常感谢您。

【问题讨论】:

  • 考虑到ReentrantLock 不工作的可能性接近于零,我建议您将this 输出到日志中,以确保您的班级是单身人士。
  • 还要检查你没有在从这个锁创建的某些条件上调用await()
  • 如果您想绝对确定,可以将锁设为静态,但从设计角度来看,这将是一场灾难
  • 你应该使用 logger.debug() 而不是 logger.warn()。如果您选择 warn() 是因为 debug() 消息没有显示在您的日志中,那么学习如何配置 log4j 可能是值得的:logging.apache.org/log4j/2.x/manual/configuration.html
  • 感谢大家。 user3707125:我将检查侦听器是否为单例,并且应用程序中不超过一个实例处于活动状态。 talex:不,await() 不会在任何地方调用。 SkinnyJ:这是我最后的资源。詹姆斯:事实上,记录器是一种自定义的记录器,出于隐私原因,我已将其显示在帖子中。也许这引起了混乱。无论如何,谢谢你的链接。

标签: java multithreading reentrantlock


【解决方案1】:

改变

logger.warn("Lock has been acquired by thread: " + Thread.currentThread().getId());

logger.warn("Lock has been acquired by thread: " + Thread.currentThread().getId() + " And Object " + System.identityHashCode(this));

您可能会看到System.identityHashCode 将是两个不同的数字。如果它是同一个对象,则 identityHashCode 将是相同的。如果它们不同,则意味着它们是不同的对象。

这告诉你有多个ReentrantLock 实例,并且不支持对不同实例的互斥。

【讨论】:

  • 非常感谢,约翰。我会执行你的建议。一旦我得到结果,我会在这里分享。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 1970-01-01
相关资源
最近更新 更多