2013-11-27 3 views
1

Я написал метод, который следует повторять 1000 раз, и метод снова представляет собой еще один цикл (например, вложенный цикл). Поскольку время выполнения не было разумным, я решил написать поток, чтобы запустить его быстрее. Вот метод:thread skips some iterations

public class NewClass implements Runnable { 
@Override 
public void run() { 
    for (int j = 0; j < 50; j++) { 
     System.out.println(i+","+j); 

     /* 
     * 
     * my method 
     */ 

    } 
    } 
} 

и вот как основной класс называет его:

for (int i = 0; i < 1000; i++) { 

    NewClass myMethod = new NewClass(); 

    Thread thread = new Thread(myMethod); 
    thread.start(); 
} 

проблема заключается в том, что, когда я запускаю его, поток пропускает первую итерацию (когда я = 0) в основном классе, а затем в следующих итерациях он пропускает некоторые итерации внутреннего цикла (myMethod). Вот результат Println:

1,0 
1,1 
2,0 
2,1 
3,0 
3,1 
3,2 
... 
3,22 
4,0 
... 

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

+2

Я не думаю, что этот код делает то, что вы думаете, что делает ... если вы хотите разделить работу между потоками, вам нужно разделить ее и дать конкретную рабочую нагрузку для каждого потока. Это чередование и в значительной степени гарантировано, что потоки будут мешать друг другу. Кроме того, используйте рамки параллелизма. Java 5 представила это десять лет назад. –

+0

i начинается с 1, как это пропустить i = 0 – JRowan

+0

@JRowan: Вы правы. Это была моя ошибка. Я починил это. – MTT

ответ

2

Ваш индекс цикла для i начинается с 1 (я предполагаю? Это даже не понятно, почему это в области), поэтому неудивительно, что i = 0 не возникает. Точно так же, я думаю, вы смущены порядком печати, который не должен быть детерминированным. Он может печатать вывод, перемежающийся с выходом из других потоков. Это нормально и ожидается. Я думаю, что код ведет себя правильно, он может просто не делать то, что вы хотите.

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

1

Как бы то ни было, нить не вызывает функцию печати, а i равна нулю. Вы не принуждаете этот заказ, поэтому он может или не может произойти в этом порядке. Любая из этих вещей может произойти.

  1. i равна нулю
  2. поток создается.
  3. Нить печатает значение i.
  4. i увеличивается.

Или

  1. i равна нулю
  2. Поток создается.
  3. i увеличивается.
  4. Нить печатает значение i.

Ваш код не предусматривает выполнение заказа, так что это может произойти в любом случае. У вас есть только гарантированный порядок между потоками, когда что-то в вашем коде гарантирует такой заказ.

+0

Большое спасибо. Как я уже говорил, я хочу распространять итерации вызова метода по потокам, но он пропускает некоторые итерации внутреннего цикла. – MTT

+0

Хорошо, что ваш код не похож на то, что вы утверждаете, что хотите сделать. –

0

ясно, что он пропускает i = 0, а для других итераций он не может закончить его. Я уверен, что проблема не в теле метода. Я запускаю его несколько раз без потока. Это первый раз, когда я пишу поток, и я думаю, что проблема в потоке.

Есть 2 причины, по которым это может случиться.

  1. Вы, кажется, распечатка i, которая является общей между потоками без какой-либо синхронизации памяти. См. tutorial on memory synchronization. Каждый процессор имеет внутреннюю кэшированную память, поэтому, хотя в основной памяти изменяется i, кэш процессора все еще может видеть старое значение.

  2. Возможно, вы также видите состояние гонки. Происходит то, что первые два потока (0 и 1) запускаются до либо из их фактически вызываемых методов run(). Поэтому, когда они оба запускают и распечатывают 1, потому что это то, что значение i в то время.

Из-за одной или обеих из этих причин, если вы запустите свое приложение 10 раз, вы увидите значительно отличающийся выход.

Если вы хотите i для совместного использования, то вы могли бы превратить его в AtomicInteger и сделать что-то вроде:

final AtomicInteger i = new AtomicInteger(0); 
... 
// replacement for your for loop 
i.set(0); 
while (true) { 
    if (i.incrementAndGet() >= 1000 { 
     break; 
    } 
    ... 
} 
... 
// inside the thread you would print 
System.out.println(i + "," + j); 

Но этот механизм не решает состояние гонки. Еще лучше было бы передать в значении i к NewClass конструктора:

private int i; 
public NetClass(int i) { 
    this.i = i; 
} 
... 

Тогда при создании экземпляров вы делаете:

NewClass myMethod = new NewClass(i);