В вашем примере есть тонкие проблемы. Во-первых, doWork
может быть совершенно бесполезным, у него нет побочных эффектов и JIT
может полностью устранить это. Подумайте об этом: поскольку l oop является чисто локальной вещью, которую никто не видит, зачем вообще это делать?
Тогда у вас как-то неправильное понимание Thread::start
, что этот ответ уже объясняет вам. t1.start();
планирует запуск потока, это не значит, что он завершится sh (или даже запустится) до t2.start();
.
Тогда, по крайней мере, ИМХО, вы используете не тот инструмент для работы. Вам нужен jcstress , инструмент, разработанный экспертами для такого рода вещей. Вот как ваш код будет выглядеть при его использовании:
@JCStressTest
@State
@Outcome(id = "0, 0", expect = Expect.FORBIDDEN, desc = "can not happen")
@Outcome(id = "0, 6", expect = Expect.ACCEPTABLE, desc = "writerY only")
@Outcome(id = "5, 6", expect = Expect.ACCEPTABLE, desc = "both")
public class TwoThreads {
volatile int x = 0;
volatile int y = 0;
@Actor
void writerX(II_Result r) {
x = 5;
}
@Actor
void writerY(II_Result r) {
y = 6;
r.r1 = x;
r.r2 = y;
}
}
Как выполнить это и что это значит - это упражнение для вас, но главное в том, что выполнение этого даст вам только два Возможные результаты:
5, 6 --> meaning writerX finished its work before writerY
или переведено в ваш код, t1
до t2
.
0, 6 --> meaning writerY finished its work before writerX
и, таким образом, x = 5
на writerX
было потеряно и никогда не записывалось. Или, переведенный в ваш код, t2
закончен до t1
.