Если у вас есть только один поток писем, вам нужен специальный concurrency?
Предполагая, что:
- Существует только один конкретный поток, который когда-либо устанавливает определенное ссылочное поле (не длинное или двойное, поэтому запись на него является атомарной)
- Есть любое количество потоков, которые могли бы прочитать это же поле
- Слегка устаревшие чтения допустимы (до нескольких секунд).
В этом случае вам нужна изменчивая или AtomicReference или что-то в этом роде?
В этой статье говорится:
Пределы памяти не требуются, если вы строго придерживаетесь принципа одиночной записи.
Кажется, что в случае, когда я описываю, вам действительно не нужно ничего особенного.
Итак, вот тест, который я провел с любопытными результатами:
import org.junit.Test;
public class ThreadTest {
int onlyWrittenByMain = 0;
int onlyWrittenByThread = 0;
@Test
public void testThread() throws InterruptedException {
Thread newThread = new Thread(new Runnable() {
@Override
public void run() {
do {
onlyWrittenByThread++;
} while (onlyWrittenByMain < 10 || onlyWrittenByThread < 10);
System.out.println("thread done");
}
});
newThread.start();
do {
onlyWrittenByMain++;
// Thread.yield();
// System.out.println("test");
// new Random().nextInt();
} while (onlyWrittenByThread < 10);
System.out.println("main done");
}
}
Иногда выполнение этого будет выводить "thread done", а затем зависать вечно. Иногда это заканчивается. Таким образом, поток видит изменения, которые делает основной поток, но, по-видимому, главное не всегда видит изменения, которые делает поток.
Если я вставил систему или Thread.yield или случайный вызов, либо сделайте onlyWrittenByThread volatile, он будет завершен каждый раз (пробовал примерно 10 + раз).
Означает ли это, что сообщение в блоге, приведенное выше, неверно? Что вы должны иметь барьер памяти даже в сценарии с одним сценарием?
Никто не ответил на этот вопрос, поэтому я думаю, что я думаю, что он, вероятно, исправит, что барьер памяти не требуется, но без чего-либо, чтобы создать взаимосвязи между событиями, java-компилятор и точка доступа могут выполнять оптимизацию (например. подъем), который заставит его не делать то, что нужно.
Ответы
Ответ 1
Проблема заключается в кешировании в многоядерной системе - без чего-то вроде волатильного форсирования взаимозависимостей (памяти-барьера) вы могли бы писать свой поток писем в копию переменной в кеше по своему ядру и всему вашему читателю потоки, читающие другую копию переменной на другом ядре. Другая проблема - атомарность, к которой обращается другой ответ.
Ответ 2
Основная проблема в вашем коде - это не столько то, что процессор будет делать, но то, что JVM будет делать с ним: у вас есть высокий риск переменного подъема. Это означает, что JMM (модель памяти Java) позволяет JVM переписать:
public void run() {
do {
onlyWrittenByThread++;
} while (onlyWrittenByMain < 10 || onlyWrittenByThread < 10);
System.out.println("thread done");
}
как этот другой фрагмент кода (обратите внимание на локальные переменные):
public void run() {
int localA = onlyWrittenByMain;
int localB = onlyWrittenByThread;
do {
localB ++;
} while (localA < 10 || localB < 10);
System.out.println("thread done");
}
Бывает, что это довольно распространенная оптимизация, созданная hotpost. В вашем случае, как только эта оптимизация будет сделана (возможно, не сразу, когда вы вызовете этот метод, но через несколько миллисекунд), то, что вы делаете в других потоках, будет никогда быть видимым из этого потока.
Ответ 3
Это необходимо, потому что изменения в поле чтения могут не отображаться для потоков чтения. Вы должны создать событие до отношения.
Ответ 4
Я думаю, вы неправильно поняли слова, которые вы указали из блога Мартина. На оборудовании x86/64 вы можете использовать Atomic *.lazySet, чтобы получить гораздо большую производительность, чем "volatile", потому что он обеспечивает барьер хранилища, который намного дешевле, чем барьер для хранения.
Насколько я понимаю, вы должны использовать AtomicLong вместо этого и использовать lazySet, чтобы гарантировать, что коды не переупорядочиваются.
Пожалуйста, обратитесь к этой статье за дополнительной информацией:
http://psy-lob-saw.blogspot.com/2012/12/atomiclazyset-is-performance-win-for.html