【问题标题】:Concurrent access to a @Lock(LockType.WRITE) method并发访问 @Lock(LockType.WRITE) 方法
【发布时间】:2014-04-24 22:49:54
【问题描述】:

我想要完成什么:

我有一个 JMS 队列,我想从该队列异步获取元素并发送到打印机。这台打印机非常具体和愚蠢,所以它不能排队或缓冲任何东西。我必须在这台打印机上按顺序执行 5 个步骤,并且排队元素的步骤不能与另一个元素的步骤重叠。对于每个步骤,打印机将在成功时返回 1,在失败时返回另一个数字。

当前的实现是一个MDB,它通过onMessage 方法从Singleton ejb 调用@Lock(LockType.WRITE) 方法。

MDB:

    @MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup",
        propertyValue = "jms/MyQueue"),
@ActivationConfigProperty(propertyName = "destinationType",
        propertyValue = "javax.jms.Queue")})

public class SimpleMessageBean implements MessageListener {

@Resource
private MessageDrivenContext mdc;
static final Logger logger = Logger.getLogger("SimpleMessageBean");

@EJB
private Print print;

public SimpleMessageBean() {
}

@Override
public void  onMessage(Message inMessage) {
    try {
        if (inMessage instanceof TextMessage) {
            logger.log(Level.INFO, "MESSAGE BEAN: Message received: {0}", inMessage.getBody(String.class));

            String params[] = ((TextMessage) inMessage).getText().split("\\s+");
            print.doStuff(params[0], params[1]);
        } else {
            logger.log(Level.WARNING,"Error")
        }
    } catch (Exception e) {
        logger.log(Level.SEVERE, "Rollback Happening: {0}", e.toString());
        mdc.setRollbackOnly();
    }
}

单身人士:

@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
@Startup
@Singleton
@AccessTimeout(value = 120000)
public class Print {

static final Logger logger = Logger.getLogger("SimpleMessageBean");

public Print() {
}

@Lock(LockType.WRITE)
public void doStuff(String cpf, String value) throws Exception{
        try{
            int return;
            return = Bematech.AbreCupom(cpf);
            System.out.println("Stage0 = " + return);

            return = Bematech.VendeItem("111112", "Parking", "FF", "hours", "1", 2, value, "%", "00,00");
            System.out.println("Stage1 = " + return);

            return = Bematech.IniciaFechamentoCupom("D", "%", "00,00");
            System.out.println("Stage2 = " + return);

            return = Bematech.EfetuaFormaPagamento("Dinheiro", value);
            System.out.println("Stage3 = " + return);

            return = Bematech.TerminaFechamentoCupom("Thankyou ofr your support");
            System.out.println("Stage4 = " + return);


        }catch ( Exception MensagemErro ){
            throw MensagemErro;
        }
}

我希望这个实现能够从队列中接收数据并在 doStuff() 方法被锁定时一次打印一个元素,AKA:

Stage0=1
Stage1=1
Stage2=1
Stage3=1
Stage4=1
Stage0=1
Stage1=1
Stage2=1
Stage3=1
Stage4=1
Stage0=1
...

但有时(似乎是随机的,但当多条消息同时排队时,这种情况更常见)我得到两个对 print 方法的并发访问:

Stage0=1
Stage1=1
Stage0=1
Stage2=1
Stage1=1
Stage3=1
Stage2=1
...

从正在打印的内容中,我可以看到 2 个元素在打印机访问中重叠。

有用的信息:

Java EE 7。 玻璃鱼 4-0。 不使用 JBOSS。

任何想法为什么会发生这种情况?

【问题讨论】:

  • 您看到的打印显示重叠,但打印机是否以正确的顺序获取命令并且一切正常?看起来打印机正在为所有命令返回 1。如果打印机命令不正常,那么我首先要检查的是您是否真的只处理了一个 Print 对象实例。如果是,那么接下来就是检查 LockType.WRITE 未按预期工作的原因。也许在 doStuff() 方法上使用 synchronized 关键字。
  • 当命令正常运行时打印机返回 1。但是由于命令重叠,打印结果也是如此,我得到的打印结果都与来自两个队列元素的东西混合在一起。至于同步关键字,它根本没有改变......至于打印对象的实例,我使用的是制造商 JAR,我如何检查我正在处理的对象的实例数量?
  • 你能发布你的实际代码吗?上面的代码在语法上不正确。 'return' 是 java 保留关键字,因此不能将其用作变量名( int return; )。如果它与您的实际代码不同,则很难找出问题所在。当您导入 @Singleton 时,您确定要导入 javax.ejb.Singleton 而不是 javax.inject.Singleton?

标签: java jakarta-ee concurrency ejb jms


【解决方案1】:

同步关键字解决了我的问题。没发现原代码有什么问题。

【讨论】:

    猜你喜欢
    • 2015-03-21
    • 1970-01-01
    • 2012-12-17
    • 2013-08-09
    • 1970-01-01
    • 2011-07-25
    • 1970-01-01
    • 2016-05-13
    • 1970-01-01
    相关资源
    最近更新 更多