Java 线程似乎运行多次

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

}

最佳答案

这个例子对我来说很难阅读,需要仔细阅读才能看到它只在最近启动的 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 对象不是线程安全的(连接在技术上是线程安全的,尽管这对应用程序开发人员没有帮助,实际上它们的使用需要一次限制在一个线程中),如果您在这部分做错了,可能会一个问题。

关于Java 线程似乎运行多次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24640204/

相关文章:

java - 通过编译参与者自定义编译器错误

java - 限制 JPQL 中的结果数量

java - Spring Boot 模型映射器 - StackOverflowError : null

c - 何时使用互斥量,何时不使用

c++ - 使用VTK和QT多线程时访​​问冲突异常

java - 使用 Hibernate/JPA 和多个 ClassLoader 来访问多个数据库

java - 带有嵌套类的instanceof运算符

java - 中断java线程中的外部方法调用

java - Java中的连续线程

c - 线程产生相同的随机数?