我一直试图在某些多线程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();
}
}
答案 0 :(得分:0)
这很难调试:)我仍然想要了解你想要达到的目标,但是你所看到的,对我而言,是正常的和预期的(如果你深入研究并理解代码)。以下是发生的事情:
CyclicBarrier设置为11.
假设主线程启动了10个其他线程,它们都开始执行其run方法。 但他们立即阻止。现在,主线程和这10个线程启动的顺序在这里并不重要。并且它并不重要因为在主线程中你第二次调用gate.await(),因此允许每个线程执行for循环。完成for循环后,它们调用gate .await() - 第二次,再次抬起障碍。
代码(我们称之为sample1):
String second = test.getValue();
if (!SECOND_VAL.equals(second)){
System.out.println("Thread " + i + " read " + second);
}
在run方法中,只有在main:
中调用之后才会执行100% unsafe.setValue(SECOND_VAL); // call it sample2
我认为问题出现在这里(魔鬼总是在细节:))。
如果你同意sample2在sample1 之前100%执行,那么这段代码的几率是多少?
if (!SECOND_VAL.equals(second)){
System.out.println("Thread " + i + " read " + second);
}
好吧,对我来说,没有。
因此我的问题是,你想证明什么?也许我们可以想到一个更好/更简单的例子?如果你仍然想要坚持这一点,那么你将不得不解释更多你想要实现的目标。