Java线程似乎不止一次运行

时间:2014-07-08 19:29:01

标签: java multithreading

有人可以向我解释以下行为吗? 鉴于此代码:

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();}

}

4 个答案:

答案 0 :(得分:0)

如果删除第一个内部循环,

,您的断言将是有效的
Thread[] threads = new Thread[100];
for(int j = 0; j<threads.length; j++) {
  //for(int i = 0; i<10; i++) {
    threads[j] = new Thread(new RunAmounts(j));
    threads[j].start();
  // }
}
for(Thread thread : threads) {
    try {
        if(thread != null)
            thread.join();
    } catch(InterruptedException ie) {
        ie.printStackTrace();
        return;
    }
}

}

答案 1 :(得分:0)

这个例子对我来说很难阅读,需要仔细阅读才能看到它只在最近启动的10个线程上调用join。数组可以被删除(除非你想保留对它们的引用以便在它们上调用中断,在这种情况下你需要一个更大的数组),Groovy中的等效功能可以像这样编写:

class RunAmounts implements Runnable {
    final int i
    public void run() {
        println i
    }
    RunAmounts(int i) {this.i = i}
}

def foo() {
    (0 .. 90).step(10).each { j ->
        (0 .. 9).each { i ->
            t = new Thread(new RunAmounts(i + j) as Runnable)
            t.start()
            t.join()
        }
    }
}

它工作正常。我可以将数组部分添加回来(在这里使用列表,但它是相同的概念)

def foo() {
    (0 .. 90).step(10).each { j ->
        threads = []        
        (0 .. 9).each { i ->
            t = new Thread(new RunAmounts(i + j) as Runnable)
            t.start()
            threads << t
        }
        threads.each { it.join() }        
    }
}

它仍然有效。

所以我认为你正在寻找错误的地方。您可以在创建此示例时编辑出真正的问题,或者您的问题出在其他地方。

如何从您的示例中编辑RunAmounts对象的数据库连接。 JDBC对象不是线程安全的(连接在技术上是线程安全的,但是对应用程序开发人员没有帮助,实际上他们的使用需要一次只限于一个线程),如果你做这个部分这可能是一个问题。

答案 2 :(得分:0)

如果您阅读本手册,您会发现我告诉您第3行可能存在添加问题。

尽管

/* thread 1 */
t1 = new Date().getTime();

/* thread 2 */
t2 = new Date().getTime();

if(t2 < t1){
  System.out.println("Your wrong with your assumption");
}
如果精度不会出现问题,那么它是不合适的。

docs.oracle.com/javase/specs/jls/se7/html/jls-17.html

使用原子操作以确保内存障碍。

我告诉你的原因并不重要。

你对时间的假设可能是错误的:

t2-t1&gt; 0

答案 3 :(得分:0)

我对时间做了一些想法,并且有一个以上的变量听起来像疯了。你的问题是计算和同步的基础。

我希望您参考我撰写的博客文章: http://sourceforge.net/p/ags/blog/2014/07/mathematical-properties-of-timing/

我在我的系统上进行线程同步,它确实不可靠并且意外崩溃即将到期。