【发布时间】:2012-02-22 22:22:05
【问题描述】:
更新:这是一个深埋在某些代码中的静态,它仅用于几条指令。谢谢大家的建议。
我们没有跨线程使用一个 HashMap(是的,这很糟糕,原因有很多)。每个线程都有自己的 HashMap。
我们有一个从 Thread 扩展而来的类。在 Thread.run() 中,我们创建一个 HashMap,在其中设置一个键/值对,然后将该 HashMap 传递给一个方法。该方法从 HashMap 中检索值,将其插入到字符串中,然后返回该字符串。
有时返回的字符串有不同的值(仍在 Thread.run() 中)。这只发生在具有 3 个以上物理内核的硬件上。而且它只发生过两次(当然,在我们添加日志记录以帮助我们准确了解发生了什么之前)。
知道为什么会发生这种情况。
更新:这是完整的代码。 ProcessTxt 是从 HashMap 中提取值并将其放入字符串中。
import java.io.*;
import java.util.HashMap;
import junit.framework.TestCase;
import net.windward.datasource.dom4j.Dom4jDataSource;
import net.windward.xmlreport.ProcessReport;
import net.windward.xmlreport.ProcessTxt;
/**
* Test calling from multiple threads
*/
public class TestThreads extends TestCase {
private static String path = ".";
// JUnit stuff
public TestThreads(String name) {
super(name);
}
// Get logging going - called before any tests run
protected void setUp() throws Exception {
ProcessReport.init();
}
// this is not necessary - called after any tests are run
protected void tearDown() {
}
private static final int NUM_THREADS = 100;
private boolean hadWithVarError = false;
/**
* Test that each thread has unique variables.
*/
public void testRunReportsWithVariables() throws Exception {
// run 10 threads
ReportThreadWithVariables[] th = new ReportThreadWithVariables[NUM_THREADS];
for (int ind = 0; ind < NUM_THREADS; ind++) {
th[ind] = new ReportThreadWithVariables(this, ind);
th[ind].setName("Run " + ind);
}
for (int ind = 0; ind < NUM_THREADS; ind++)
th[ind].start();
boolean allDone = false;
while (!allDone) {
Thread.sleep(100);
allDone = true;
for (int ind = 0; ind < NUM_THREADS; ind++)
if (th[ind].isAlive())
allDone = false;
}
assertTrue(!hadWithVarError);
}
public static class ReportThreadWithVariables extends Thread {
private TestThreads obj;
private int num;
public ReportThreadWithVariables(TestThreads tt, int num) {
obj = tt;
this.num = num;
}
public void run() {
try{
System.out.println("starting " + num);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ProcessTxt pt = new ProcessTxt(new FileInputStream(new File(path, "Thread_Test.docx")), out);
pt.processSetup();
// don't use order1.xml, but need a datasource.
Dom4jDataSource datasource = new Dom4jDataSource(new FileInputStream(new File(path, "order1.xml")));
HashMap map = new HashMap();
map.put("num", new Integer(num));
datasource.setMap(map);
pt.processData(datasource, "");
pt.processComplete();
String result = out.toString().trim();
System.out.println("complete " + num + ", result = " + result);
String expected = "Number: " + num;
if (!result.equals( expected ))
obj.hadWithVarError = true;
assertEquals(expected, result);
} catch (Throwable e) {
obj.hadWithVarError = true;
e.printStackTrace();
}
}
}
}
(编辑格式代码)
【问题讨论】:
-
关键是什么?一个简短但完整的程序来演示这个问题会真的帮助...
-
值的类型也可能是相关的。这些值是否可能包含一个在其他地方被引用并随后被修改的对象?
-
您发布的代码写得不太好。您可能会发现进行常规代码清理可以解决您的问题。例如,即使您对 hadWithVarError 的处理也很激烈......它“听起来应该可以工作”,但由于指定 Java 内存模型的方式,您必须正确同步(或标记 volatile)甚至是简单的布尔字段。
-
除非我遗漏了什么单元测试是错误的。您永远不会写入 ByteArrayOutputStream 'out',而是从中读取 'result'