Похоже, что потоки Java работают более одного раза

1

Может ли кто-нибудь объяснить мне следующее поведение? Учитывая этот код:

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, но каждый номер заканчивается печать несколько раз. Может ли кто-нибудь объяснить это свойство потоков?

EDIT: может быть, из-за 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
    @ Там нет 1 + 9
  • 1
    опубликовать свой run() RunAmount
Показать ещё 2 комментария
Теги:
multithreading

4 ответа

0
Лучший ответ

Этот пример был трудным для меня читать, он требует некоторого тщательного чтения, чтобы увидеть, что он только вызывает соединение в последних 10 потоках. Массив можно избавиться (если вы не хотите придерживаться ссылки на них, чтобы вызвать прерывание на них, и в этом случае, конечно, вам нужен больший массив), эквивалентная функциональность в 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 не являются потокобезопасными (соединения являются технически потокобезопасными, хотя это не полезно для разработчиков приложений, поскольку практическое значение их использования должно ограничиваться одним потоком за раз), если вы делаете эту часть неправильно, это может быть проблема.

  • 0
    Извините, я поспешно удалил большую часть кода, чтобы попытаться упростить его, и в итоге получился довольно запутанный
0

Я сделал некоторые мысли о сроках, и все, что больше, чем одна переменная, звучит как безумие. Ваша проблема довольно фундаментальна для вычислений и синхронизации.

Я хотел бы, чтобы вы ссылались на сообщение в блоге, которое я написал: http://sourceforge.net/p/ags/blog/2014/07/mathematics-properties-of-timing/

Я выполняю синхронизацию потоков в своей системе, и это действительно ненадежно и заканчивается неожиданными сбоями.

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

}

  • 0
    С моим кодом 0-99 все равно должен быть результат, возможно, не в таком порядке, но вместо печати 100 значений он печатает около 1000
  • 0
    Вы уверены, что нет другой петли?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню