Индекс выходит за пределы при добавлении в ArrayList

Редактировать: просто чтобы указать, что я знаю, что обычно означает индекс за пределами границ - я бы не делал этот пост, если бы это не было чем-то, с чем я никогда раньше не сталкивался, что в данном случае представляет собой массив список который отказывается добавлять простое старое целое число 6000 или около того и массив байтов размером 2 мил...

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

У меня есть программа для поиска простых чисел, меньших заданного числа n (решето Эратосфена), которую я распараллелил. В нем я выделил все числа, не являющиеся простыми до n, в массиве байтов, и у меня есть ArrayList, содержащий найденные мной простые числа.

Сначала я просто складываю числа до sqrt(n) и отмечаю все найденные произведения простых чисел (поэтому, если я нахожу 5, я отмечаю: 5*5, и 5*5 + 2*5, и 5*5 + 3*5 и т. д.), так что, найдя все простые числа до квадратного корня из n, я вычеркнул все числа, не являющиеся простыми, между sqrt(n) до n.

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

  public void addRemainingPrimes(int start, int end){

    for(int i = start; i < end; i+= 2){
      if(isPrime(i)){
        primes.add(i);
      }
    }
  }

  public boolean isPrime(int i) {
      int byteCell    = i / 16;
      int bit         = (i/2) % 8;
      return (numbers[byteCell] & (1 << bit)) == 0;

  }

В классе потоков:

public void run(){
  //does stuff to find primes up to sqrt(n)

  updateRange();
  addRemainingPrimes(start, end);

}

public void updateRange(){
  if(id == 0){
    start = sqrt;
  }else{
    start = (((n - sqrt)/k) * id) + sqrt;
  }
  if(id == k-1){
    end = n;
  }else{
    end = start + ((n - sqrt) / k) - 1;
  }

}

числа — это байтовый массив размера n, простые числа — это мой ArrayList простых чисел, n = 2.000.000, k — количество потоков, которые я использую, а id — от 0 до k-1.

Ошибка, которую я получаю:

Exception in thread "Thread-5" java.lang.ArrayIndexOutOfBoundsException: 6246
    at java.util.ArrayList.add(ArrayList.java:463)
    at ParallellSieve.addRemainingPrimes(ParallellSieve.java:162)
    at ParallellSieve$PrimeWorker.run(ParallellSieve.java:194)
    at java.lang.Thread.run(Thread.java:748)

person Telanore    schedule 22.03.2018    source источник
comment
можете ли вы отладить, чтобы указать, где исключение, а затем зафиксировать значение i ?. Оно может быть меньше 0 или больше Integer.MAX_VALUE . проверьте свой с вами отладчик.   -  person arthur    schedule 22.03.2018
comment
(Извините, я сегодня идиот) Я сделал это, и это дало мне, что я = 27918, так что это должно быть много в пределах диапазона. Кажется, он меняется каждый раз, когда я его запускаю, поэтому, может быть, мне нужно синхронизировать добавление в список?   -  person Telanore    schedule 22.03.2018
comment
Это действительно была проблема параллелизма. Добавление нескольких потоков к одному и тому же ArrayList может привести к тому, что он не обновит новый размер списка должным образом, что приведет к исключению выхода за пределы.   -  person Telanore    schedule 22.03.2018