1


Я в настоящее время работаю на мое первое многопоточного программного обеспечения - программа, которая вычисляет простые числа ...
В основном я создаю п (число нитей) runnables. Эти runnables добавляются в ArrayList. Они проверяют, является ли число простым. Если число является простым, я добавляю его в длинный массив для последующего использования. Поскольку я хочу, чтобы простые числа были в правильном порядке в этом массиве, мне нужны конкретные потоки, чтобы ждать других. Я делаю это, перебирая ArrayList (см. Выше) и дожидаясь потоков, которые проверяют меньшее число.
После того, как поток сделан, я хочу удалить его из заданного ArrayList, но я не могу, потому что другие потоки все еще проходят через него (Вот почему возникает ConcurrentModificationException, я думаю - это мой первый опыт работы с потоками. ..).Java Тема с ConcurrentModificationException


Я искренне надеюсь, что любой из вас, ребята, может мне помочь :)
Спасибо, очень много!

Matthias

Мой работоспособной класс ( я просто создать четыре объекта этого класса в основном методе):

импорт java.util.ArrayList;

public class PrimeRunnable implements Runnable { 

    //Static Util 
    public static ArrayList<PrimeRunnable> runningThreads = new ArrayList<PrimeRunnable>(); 
    public static long[] primes; 
    public static int nextFreeIndex = 1; 
    public static long nextPossiblePrime = 3; 

    //Object specific 
    private long numberToCheck; 
    private Thread primeThread; 
    private String threadName; 
    private long threadID; 

    public PrimeRunnable() { 
     numberToCheck = nextPossiblePrime; 
     increaseNextPossiblePrime(); 

     threadName = "ThreadToCheck" + numberToCheck; 
     threadID = numberToCheck; 

     runningThreads.add(this); 
    } 

    @Override 
    public void run() { 
     boolean isPrime = true; 
     double sqrtOfPossiblePrime = Math.sqrt(numberToCheck); 

     long lastDevider = 0; 

     for(int index = 0; index < nextFreeIndex; index++) { 
      lastDevider = primes[index]; 
      if(numberToCheck%primes[index] == 0) { 
       isPrime = false; 
       break; 
      } 
      if(primes[index] > sqrtOfPossiblePrime) { 
       break; 
      } 
     } 

     while(lastDevider < sqrtOfPossiblePrime) { 
      lastDevider += 1; 

      if(numberToCheck%lastDevider == 0) { 
       isPrime = false; 
       break; 
      } 
     } 

     if(isPrime) { 
      //Wait for lower Threads. 

      for(PrimeRunnable runnable : runningThreads) { 
       if(runnable.getThreadID() < this.getThreadID()) { 
        try { 
         runnable.primeThread.join(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 

      primes[nextFreeIndex] = numberToCheck; 
      increaseNextFreeIndex(); 
      System.out.println(numberToCheck); 
     } 
     runningThreads.remove(this); 
    } 

    public void start() { 
     if(primeThread == null) { 
      primeThread = new Thread(this, threadName); 
     } 

     primeThread.start(); 
    } 

    public void reset() { 
     numberToCheck = nextPossiblePrime; 
     increaseNextPossiblePrime(); 

     threadName = "ThreadToCheck" + numberToCheck; 
     threadID = numberToCheck; 

     //No need to readd into runningThread, since we only manipulate an already existing object. 
     primeThread = new Thread(this, threadName); 
     primeThread.start(); 
    } 

    public static void setUpperBorder(int upperBorder) { 
     if(primes == null) { 
      primes = new long[upperBorder]; 
      primes[0] = 2; 
     } else { 
      System.err.println("You are not allowed to set the upper border while running."); 
     } 
    } 

    public long getNumberToCheck() { 
     return numberToCheck; 
    } 

    private void increaseNextPossiblePrime() { 
     nextPossiblePrime += 2; 
    } 

    private void increaseNextFreeIndex() { 
     nextFreeIndex += 2; 
    } 

    public long getThreadID() { 
     return threadID; 
    } 

    public boolean isAlive() { 
     return primeThread.isAlive(); 
    } 
} 
+0

Пожалуйста, пост трассировка стека. – pathfinderelite

+0

Попробуйте использовать потокобезопасные коллекции, такие как Vector или синхронизировать ArrayList runningThreads и long [] primes. – isma3l

+0

Что-то вызывает подозрение в вашем методе 'start()'. Вы знаете, что «Thread» может быть запущен только один раз? Ваш метод 'PrimeRunnable.start()' выглядит так, как будто вы его называли более одного раза. –

ответ

0

Я был в состоянии воспроизвести проблему и исправить его с помощью реализации Java из одновременных списка CopyOnWriteArrayList

Вот мой основной класс

public class PrimeRunnableMain { 

    public static void main(String[] args) { 
     PrimeRunnable.setUpperBorder(10); 
     PrimeRunnable primeRunnable1 = new PrimeRunnable(); 
     PrimeRunnable primeRunnable2 = new PrimeRunnable(); 
     PrimeRunnable primeRunnable3 = new PrimeRunnable(); 
     PrimeRunnable primeRunnable4 = new PrimeRunnable(); 
     primeRunnable1.start(); 
     primeRunnable2.start(); 
     primeRunnable3.start(); 
     primeRunnable4.start(); 
    } 
} 

и вот PrimeRunnable

import java.util.ArrayList; 
import java.util.List; 
import java.util.concurrent.CopyOnWriteArrayList; 

public class PrimeRunnable implements Runnable { 

    // Static Util 
    public static List<PrimeRunnable> runningThreads = new CopyOnWriteArrayList<PrimeRunnable>(); 
    public static long[] primes; 
    public static int nextFreeIndex = 1; 
    public static long nextPossiblePrime = 3; 

    // Object specific 
    private long numberToCheck; 
    private Thread primeThread; 
    private String threadName; 
    private long threadID; 

    public PrimeRunnable() { 
     numberToCheck = nextPossiblePrime; 
     increaseNextPossiblePrime(); 

     threadName = "ThreadToCheck" + numberToCheck; 
     threadID = numberToCheck; 

     runningThreads.add(this); 
    } 

    @Override 
    public void run() { 
     boolean isPrime = true; 
     double sqrtOfPossiblePrime = Math.sqrt(numberToCheck); 

     long lastDevider = 0; 

     for (int index = 0; index < nextFreeIndex; index++) { 
      lastDevider = primes[index]; 
      if (numberToCheck % primes[index] == 0) { 
       isPrime = false; 
       break; 
      } 
      if (primes[index] > sqrtOfPossiblePrime) { 
       break; 
      } 
     } 

     while (lastDevider < sqrtOfPossiblePrime) { 
      lastDevider += 1; 

      if (numberToCheck % lastDevider == 0) { 
       isPrime = false; 
       break; 
      } 
     } 

     if (isPrime) { 
      // Wait for lower Threads. 

      for (PrimeRunnable runnable : runningThreads) { 
       if (runnable.getThreadID() < this.getThreadID()) { 
        try { 
         runnable.primeThread.join(); 
        } catch (InterruptedException e) { 
         e.printStackTrace(); 
        } 
       } 
      } 

      primes[nextFreeIndex] = numberToCheck; 
      increaseNextFreeIndex(); 
      System.out.println(numberToCheck); 
     } 
     runningThreads.remove(this); 
    } 

    public void start() { 
     if (primeThread == null) { 
      primeThread = new Thread(this, threadName); 
     } 

     primeThread.start(); 
    } 

    public void reset() { 
     numberToCheck = nextPossiblePrime; 
     increaseNextPossiblePrime(); 

     threadName = "ThreadToCheck" + numberToCheck; 
     threadID = numberToCheck; 

     // No need to readd into runningThread, since we only manipulate an 
     // already existing object. 
     primeThread = new Thread(this, threadName); 
     primeThread.start(); 
    } 

    public static void setUpperBorder(int upperBorder) { 
     if (primes == null) { 
      primes = new long[upperBorder]; 
      primes[0] = 2; 
     } else { 
      System.err 
        .println("You are not allowed to set the upper border while running."); 
     } 
    } 

    public long getNumberToCheck() { 
     return numberToCheck; 
    } 

    private void increaseNextPossiblePrime() { 
     nextPossiblePrime += 2; 
    } 

    private void increaseNextFreeIndex() { 
     nextFreeIndex += 2; 
    } 

    public long getThreadID() { 
     return threadID; 
    } 

    public boolean isAlive() { 
     return primeThread.isAlive(); 
    } 
} 
+0

Спасибо, очень много! Кажется, я понял! – Matthias

+0

Ничего себе, сейчас программа - но, мм ... это WAAAYY медленнее, чем многопоточная версия ... Посмотрите мое редактирование, пожалуйста (: – Matthias

0

насчет PrimeListener класса, который содержит синхронизированный метод publishPrime, который вставляет штрих в правильном положении в списке? Вставка в нужное положение в списке не должна занимать слишком много времени, если вы начинаете с последнего индекса LinkedList.

В качестве альтернативы вы также можете вставить его в SortedSet (исполнение: TreeSet). Я предполагаю, что вы не хотите, чтобы в любом случае были дубликаты простых чисел. В этом случае synchronizedSortedSet может использоваться непосредственно вместо слушателя.

Обратите внимание, что вы по-прежнему кажутся довольно застрявшими на структурах нижнего уровня. При одновременном программировании на Java он рассчитывает использовать конструкции более высокого уровня (исполнители, фьючерсы, параллельные очереди и т. Д.).

0

Основное различие между отказоустойчивым быстро и отказоустойчивыми итераторами ли не сбор может быть изменен во время его итерации. Истребители с безопасностью позволяют это; отказоустойчивые итераторы этого не делают.

Неуправляемые итераторы работают непосредственно на самой коллекции. В течение итерация с ошибками итераторов сбой, как только они осознают, что коллекция была изменена (т. Е. При понимании того, что элемент имеет , был добавлен, изменен или удален) и будет вызывать исключение ConcurrentModificationException . Некоторые примеры включают ArrayList, HashSet и HashMap (большинство коллекций JDK1.4 реализованы как с ошибкой). Истерические итерации работают с клонированной копией коллекции и поэтому не генерируют исключения, если коллекция изменяется во время итерации. Примеры включают итераторы , возвращаемые ConcurrentHashMap или CopyOnWriteArrayList.

Смежные вопросы