有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

}

共 (2) 个答案

  1. # 1 楼答案

    这个示例对我来说很难理解,需要仔细阅读才能看到它只在最近启动的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. # 2 楼答案

    如果删除第一个内部循环,您的断言将有效

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

    }