Модель памяти Java в синхронизированном блоке

Я запутался о модели памяти в Java, пример, как следующий код:

 /**
  * one thread write request and wait for response
  */
public AbstractPacket writeMessageAndWaitForResp(AbstractPacket packet, int waitTimeoutInSecond) {
        if (!(packet instanceof SendToRouter)) {
            throw new IllegalArgumentException("this msg can not be sent to router!");
        }

        int command = packet.getResponseCommand();
        AbstractPacket[] slot = new AbstractPacket[]{NullPacket.NULL};
        synchronized (("" + this.getFactoryId() + this.getRouterNo() + command).intern()) {// prevent same command request re-entry
            command2RespMap.put(command, slot);
            synchronized (slot) { // prevent notify before wait
                ChannelFuture future = writeMessage(packet);
                if (future == null) {
                    command2RespMap.remove(command);
                    return null;
                }

                try {
                    slot.wait(waitTimeoutInSecond * 1000);
                } catch (InterruptedException e) {
                    logger.error(e.getMessage(), e);
                }
            }
            command2RespMap.remove(command);
        }
        AbstractPacket result = slot[0]; // get out the result outof slot array
        if (result == NullPacket.NULL) {
            logger.error("receive sync message timeout!");
            return null;
        }
        return result;
}

 /**
  * another thread write response and notify the waiter
  */
 public void routerResponse(AbstractPacket packet) {
        int command = packet.getHeadCommand();
        AtomicReference<AbstractPacket> slot = command2RespMap.get(command);
        if (slot == null || slot.get() != NullPacket.NULL) {
            logger.error("command : {} request not exist !", command);
            return;
        }
        synchronized (slot) {
            slot[0] = packet;
            slot.notify();
        }
}

Мой вопрос заключается в том, что в первой функции я получил результат из слота с индексом 0 из синхронизированного блока переменной слота.

Означает ли это, что слот [0] может не содержать значение, установленное второй функцией в другом потоке?

большое спасибо!

1 ответ

synchronized ключевые слова, как барьер памяти, гарантирует 2 вещи

  1. Компилятор может поменять местами порядок некоторых операторов в вашей программе. Однако, увидев синхронизированный блок, любой оператор в блоке не будет переупорядочен или смешан с операторами за пределами синхронизированного блока.

  2. Внутри блока любые переменные будут получать свое значение из основной памяти, а локальная копия потока и / или кэшированное значение L2-кэша / регистра будут отбрасываться. По окончании блока измененные в блоке переменные будут записаны обратно в основную память, чтобы все другие потоки считывали одно и то же значение.

Таким образом, поскольку вы ссылаетесь на slot[0] вне синхронизированного блока, нет никакой гарантии, что эта ссылка будет соответствовать значению, которое вы обновили внутри синхронизированного блока, а также нет гарантии, будет ли это локальное кэшированное значение потока или из основная память.

Кстати, как упомянул @chrylis, ваш блок очень дорогой, и вам нужно подумать хотя бы о том, чтобы убрать wait().

Другие вопросы по тегам