Параллельный доступ к методу @Lock (LockType.WRITE)

1

Что я пытаюсь сделать:

У меня есть очередь JMS, и я хочу асинхронно получить элементы из этой очереди и отправить на принтер. Этот принтер очень конкретный и немой, поэтому он не может стоять в очереди на нем или вообще ничего не хранить. Я должен выполнить 5 шагов в последовательности на этом принтере, и шаги очереди elemet не должны перекрывать шаги другого элемента. Для каждого шага принтер вернет 1 при успешном завершении, а другой - при сбое.

Текущая реализация - это MDB с вызовом метода onMessage для метода @Lock (LockType.WRITE) из синглтона ejb.

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
...

Но иногда (кажется случайным, но это происходит чаще, когда сразу несколько сообщений помещаются в очередь), я получаю два одновременных доступа к методу печати:

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

Из того, что печатает, я вижу, что в доступе принтера перекрываются 2 элемента.

Полезная информация:

Java EE 7. Glassfish 4-0. Не использовать JBOSS.

Есть идеи, почему это происходит?

Теги:
concurrency
java-ee
ejb
jms

1 ответ

1
Лучший ответ

Синхронизированное ключевое слово решило мою проблему. Не понял, что было не так с исходным кодом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню