Я пытаюсь справиться с JCStress. Чтобы я понял это, я решил написать несколько простых тестов для чего-то, что, как я знаю, должно быть правильным: java.util.concurrent.locks.ReentrantReadWriteLock
.
Я написал несколько очень простых тестов для проверки совместимости режима блокировки. К сожалению, два стресс-теста не срабатывают:
-
X_S
:true, true 32,768 FORBIDDEN No default case provided, assume FORBIDDEN
-
X_X
:true, true 32,767 FORBIDDEN No default case provided, assume FORBIDDEN
Мне кажется, что один поток не может удерживать блокировку чтения, в то время как другой поток также содержит блокировку записи. Аналогичным образом, для двух потоков одновременное удерживание блокировки записи должно быть невозможным.
Я понимаю, что проблема, скорее всего, не с ReentrantReadWriteLock
. Я полагаю, что я, вероятно, делаю какую-то глупую ошибку в своих тестах jcstress в отношении JMM и читаю состояние замков.
К сожалению, я не могу определить проблему. Может кто-то, пожалуйста, помогите мне понять (тупую?) Ошибку, которую я сделал?
import org.openjdk.jcstress.annotations.*;
import org.openjdk.jcstress.infra.results.ZZ_Result;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/*
* |-----------------|
* | COMPATIBILITY |
* |-----------------|
* | | S | X |
* |-----------------|
* | S | YES | NO |
* | X | NO | NO |
* |-----------------|
*/
public class ReentrantReadWriteLockBooleanCompatibilityTest {
@State
public static class S {
public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
public boolean shared() {
return lock.readLock().tryLock();
}
public boolean exclusive() {
return lock.writeLock().tryLock();
}
}
@JCStressTest
@Outcome(id = "true, true", expect = Expect.ACCEPTABLE, desc = "T1 and T2 are both acquired S")
public static class S_S {
@Actor
public void actor1(S s, ZZ_Result r) { r.r1 = s.shared(); }
@Actor
public void actor2(S s, ZZ_Result r) { r.r2 = s.shared(); }
}
@JCStressTest
@Outcome(id = "true, false", expect = Expect.ACCEPTABLE, desc = "T1 acquired S, and T2 could not acquire X")
@Outcome(id = "false, true", expect = Expect.ACCEPTABLE, desc = "T2 acquired X, and T1 could not acquire S")
public static class S_X {
@Actor
public void actor1(S s, ZZ_Result r) { r.r1 = s.shared(); }
@Actor
public void actor2(S s, ZZ_Result r) { r.r2 = s.exclusive(); }
}
@JCStressTest
@Outcome(id = "true, false", expect = Expect.ACCEPTABLE, desc = "T1 acquired X, and T2 could not acquire S")
@Outcome(id = "false, true", expect = Expect.ACCEPTABLE, desc = "T2 acquired S and T1 could not acquire X")
public static class X_S {
@Actor
public void actor1(S s, ZZ_Result r) { r.r1 = s.exclusive(); }
@Actor
public void actor2(S s, ZZ_Result r) { r.r2 = s.shared(); }
}
@JCStressTest
@Outcome(id = "true, false", expect = Expect.ACCEPTABLE, desc = "T1 acquired X, and T2 could not acquire X")
@Outcome(id = "false, true", expect = Expect.ACCEPTABLE, desc = "T2 acquired X and T1 could not acquire X")
public static class X_X {
@Actor
public void actor1(S s, ZZ_Result r) { r.r1 = s.exclusive(); }
@Actor
public void actor2(S s, ZZ_Result r) { r.r2 = s.exclusive(); }
}
}
Я попытался спросить об этом на jcstress-dev
но так и не получил ответа - http://mail.openjdk.java.net/pipermail/jcstress-dev/2018-August/000346.html. Извинения за перекрестную рассылку, но мне нужна помощь в этом, и поэтому я переписываю StackOverflow в надежде привлечь внимание более широкой аудитории.