我一直试图在一些多线程 Java 代码中引发发布错误。
下面的示例似乎应该可以解决问题,但到目前为止它按预期运行。不可否认,我在只有两个内核(和超线程)的 MacBook Pro(OSX 10.7.4 和 2.8 GHz Intel Core i7)上运行它。所以一次只能运行 4 个线程。
任何想法如何更好地引发出版失败?
package demo;
import java.util.concurrent.CyclicBarrier;
public class UnsafePublicationTest {
private static final String FIRST_VAL = "FAIL";
private static final String SECOND_VAL = "GOOD";
public void test() throws Exception {
UnsafePublisher unsafe = new UnsafePublisher();
unsafe.setValue(FIRST_VAL);
CyclicBarrier gate = launchThreads(10, unsafe);
gate.await(); // Start all threads at once
gate.await(); // Each thread reads the first value
// Should cause errors since update is not published
unsafe.setValue(SECOND_VAL);
gate.await(); // Each thread tries for the second value
gate.await(); // Wait for the readers finish
}
private CyclicBarrier launchThreads(int count, UnsafePublisher unsafe) {
CyclicBarrier gate = new CyclicBarrier(count + 1);
for (int id = 0; id < count; id++) {
ValueReader rdr = new ValueReader(id, gate, unsafe);
rdr.start();
}
return gate;
}
private static class UnsafePublisher {
private String fValue;
public UnsafePublisher() { /* no synthetic ctor */ }
public void setValue(String value) {
this.fValue = value;
}
public String getValue() {
return fValue;
}
}
private static class ValueReader extends Thread {
private final int fId;
private final CyclicBarrier fGate;
private final UnsafePublisher fTest;
public ValueReader(int id, CyclicBarrier gate, UnsafePublisher test) {
fId = id;
fGate = gate;
fTest = test;
}
public void run() {
try {
fGate.await();
int noOp = this.hashCode();
// Try to get the thread to cache the value.
for (int i = 0; i < 10000; i ++) {
for (int j = 0; j < 10000; j++) {
String first = fTest.getValue();
noOp = noOp ^ first.hashCode();
if (!FIRST_VAL.equals(first))
System.out.println("Thread " + fId + " read " + first);
}
}
fGate.await();
// Between these awaits, the value is changed.
fGate.await();
String second = fTest.getValue();
if (!SECOND_VAL.equals(second))
System.out.println("Thread " + fId + " read " + second);
System.out.println("Thread " + fId + " hash " + noOp);
fGate.await();
} catch (Exception err) { /* ignore */ }
}
}
public static void main(String[] args) throws Exception {
UnsafePublicationTest test = new UnsafePublicationTest();
test.test();
}
}