Модель памяти 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 вещи
Компилятор может поменять местами порядок некоторых операторов в вашей программе. Однако, увидев синхронизированный блок, любой оператор в блоке не будет переупорядочен или смешан с операторами за пределами синхронизированного блока.
Внутри блока любые переменные будут получать свое значение из основной памяти, а локальная копия потока и / или кэшированное значение L2-кэша / регистра будут отбрасываться. По окончании блока измененные в блоке переменные будут записаны обратно в основную память, чтобы все другие потоки считывали одно и то же значение.
Таким образом, поскольку вы ссылаетесь на slot[0] вне синхронизированного блока, нет никакой гарантии, что эта ссылка будет соответствовать значению, которое вы обновили внутри синхронизированного блока, а также нет гарантии, будет ли это локальное кэшированное значение потока или из основная память.
Кстати, как упомянул @chrylis, ваш блок очень дорогой, и вам нужно подумать хотя бы о том, чтобы убрать wait().