多线程Java线程似乎运行了不止一次
有人能给我解释一下下面的行为吗? 鉴于此代码:
for(int j = 0; j<100; j+=10) {
for(int i = 0; i<10; i++) {
threads[i] = new Thread(new RunAmounts(i+j));
threads[i].start();
}
for(Thread thread : threads) {
try {
if(thread != null)
thread.join();
} catch(InterruptedException ie) {
ie.printStackTrace();
return;
}
}
System.gc();
}
假设RunAmounts只打印其参数。人们希望每个数字0-99只打印一次,但每个数字最终都会打印几次。有人能解释线程的这个属性吗
编辑:可能是因为run(),实际上,代码将唯一的pageNum传递给RunAmounts,并将其附加到SQL语句中
class RunAmounts extends Thread {
private int pageNum;
public RunAmounts(int pageNum) {
this.pageNum = pageNum;
}
public void run() {
ResultSet rs = null;
String usdAmt, row[] = new String[5], extr[] = new String[3];
LinkedList<String[]> toWrite = new LinkedList<String[]>();
CSVWriter fw = null;
boolean cont;
try {
fw = new CSVWriter(new FileWriter("Amounts.csv", true), ',');
do {
//executes SQL command, initializes rs & pst
cont = pst.execute();
while(rs.next()) {
//does a bit of parsing
toWrite.addFirst(row);
synchronized(this) {
fw.writeAll(toWrite);
fw.flush();
}
toWrite.clear();
}
System.out.println("page: " + Integer.toString(pageNum));
rs.close();
} while(cont);
fw.close();
} catch(Exception e) {e.printStackTrace();}
}
# 1 楼答案
这个示例对我来说很难理解,需要仔细阅读才能看到它只在最近启动的10个线程上调用join。可以去掉数组(除非您想保留对这些数组的引用,以便对它们调用中断,在这种情况下,您当然需要一个更大的数组),Groovy中的等效功能可以这样编写:
而且效果很好。我可以重新添加数组部分(使用此处的列表,但概念相同)
它仍然有效
所以我觉得你找错地方了。要么你在创建这个示例时删掉了真正的问题,要么你的问题在其他地方
如何获得RunAmounts对象的数据库连接是根据您的示例编写的。JDBC对象不是线程安全的(连接在技术上是线程安全的,尽管在某种程度上对应用程序开发人员没有帮助,但实际上它们的使用需要一次只限于一个线程),如果这部分做得不对,可能会出问题
# 2 楼答案
如果删除第一个内部循环,您的断言将有效
}